cin.getline не выполняется c ++ - PullRequest
0 голосов
/ 25 июля 2011

По какой-то странной причине моя строка ввода cin.getline(oneLine, 80); полностью игнорируется, когда я помещаю ее в блок else.Я не могу понять почему, потому что, когда я перемещаю его куда-то еще в программе, это работает.

     else if (choice == "user-id")
     {   
        cout << endl << "Enter a full name e.g. John Smith ";
        char oneLine[80];
        cin.getline(oneLine, 80);
        cout << oneLine;                        
     }

Вот остаток моего кода.Я новичок в C ++, поэтому я уверен, что многие из моих соглашений могут быть в лучшем случае сомнительными.

int main( )
{
    while (true)
        {

        int pause;
        string choice = "proceed";
        string nameGiven;
        string userIdGiven;
        string result;
        using namespace std ;

        while ((choice != "name") && (choice != "user-id"))
        {   
            cout << "Would you like to search for a name or user-id? ";
            cin >> choice;
            if ((choice != "name") && (choice != "user-id"))
               cout <<"Please enter a valid choice (name or user-id)" << endl;
        }

        if (choice == "name") 
        {
            string dataType = "int";
            while (true)
            {    
                cout << endl << "Enter a valid user id (4 digit maximum) ";
                cin >> userIdGiven;

                if (valid(userIdGiven))
                   break;
                else
                    cout << endl << "Not a valid number. " << endl;
                   continue;
             }
             result = findData(userIdGiven, dataType);
             cout << "name: " << result;

         }

         else if (choice == "user-id")
         {   
            cout << endl << "Enter a full name e.g. John Smith ";
            char oneLine[80];
            std::getline(oneLine, 80);
            cout << oneLine;                       
         }

        string ans;
        cout << endl << "Would you like to play again? (yes/no) " << endl;
        cin >> ans;
        if ( (ans == "yes") || (ans == "Yes") || (ans == "Y") || (ans == "y") )
             continue;
          else
              break;

        cin >> pause;
     } 
return 0;
}

Ответы [ 3 ]

2 голосов
/ 25 июля 2011

Ваш std::cin объект находится в плохом состоянии (std::cin.good() == false) от предыдущей операции ввода.Например, вы, возможно, пытались прочитать число, но во входном буфере были только числовые символы.

Всегда проверяйте успешность ввода, прежде чем продолжать использовать std::istream.

Примечание: Не используйте старые функции ввода, работающие с char*, поскольку они более сложны и менее безопасны в использовании, чем новые, работающие на std::string.В вашем случае используйте std::getline(std::istream&, std::string&, char = '\n').

1 голос
/ 25 июля 2011

комментарий twsaef по существу правильный ... вы передаете строку в выбор, которая потребляет символы до, но исключая следующий пробельный символ - вы, вероятно, вводите новую строку, чтобы завершить ввод, так что она остается в буфере,Затем вы используете getline, который видит эту новую строку и читает пустую строку.

Самое простое решение - вызвать getline(), чтобы тоже прочитать начальную строку, а затем проверить, является ли выбор "name \ n" или "user-id\ п».Лучше - написать функцию «обрезки», чтобы удалить пробелы из строки перед сравнением (в библиотеке ускоренных строк это уже есть).В противном случае вы можете использовать чтение и игнорировать символы от std::cin, пока не получите '\ n'.Или даже прочитайте строку, затем вставьте ее в поток строк и прочитайте строку оттуда .... Много вариантов.

И, пожалуйста, проверьте состояние своего потока!Попробуйте использовать:

if (std::cin >> x)
    // x was parsed from stream... use it
else
    // print an error so you know where things failed!
0 голосов
/ 25 июля 2011

FWIW, я догадался, в чем проблема (это глупо распространено), прежде чем увидел обновление, и посмеялся про себя при других догадках (хотя они дают очень хорошие замечания, даже если пропустили проблему ОП).

Строка кода работает правильно и в соответствии с объявлением. Это не работает так, как вы хотите.

Когда вы читаете из std :: cin, не приостанавливает программу и ожидает ввода. Причиной паузы является отсутствие достаточных входных данных для операции чтения.

Вход подается в вашу программу по очереди. Помните, что консольное окно - это тоже программа. Он отвечает за преобразование нажатий клавиш пользователем в текстовые символы (в действительности, байты), обработку таких вещей, как клавиша возврата и сбор всего текста в строки.

Допустим, вы прочитали int с помощью operator>>, а затем прочитали строку с getline. Программа не увидит int, пока пользователь не нажмет клавишу Return, потому что это заставит консоль передать строку ввода в вашу программу.

operator>> пропустит пробел пробела, прочитает целое число, а оставит только пробел . Символы новой строки являются пробелами. На входе есть символ новой строки (очевидно, в конце строки).

getline() не будет пропустить ни одного начального пробела и будет читать до следующего символа новой строки. Самым следующим символом является символ новой строки, поэтому getline() с радостью читает пустую строку, и программа продолжает это.

Так как вы это исправите? Скорее всего, если вы читаете все свои входные данные из cin, вы хотите, чтобы программа приостанавливала каждый раз, когда вы приходите к операции чтения. Способ сделать это состоит в том, чтобы в этот момент никогда не было доступных данных, и способ сделать это - прочитать все, что доступно, то есть всю строку, каждый раз, когда вы что-то читаете.

Итак, всегда читайте полную строку из cin. Как отмечает wilx, используйте для этого бесплатную функцию std::getline. Не используйте функцию-член .getline потока. Используйте std::string для представления строк текста. Вот для чего это. Это сделает вашу жизнь намного, намного проще. Это также означает, что если вы ожидаете целое число и пользователь вводит «76 тромбонов», вы избавляетесь от данных «тромбонов» (и можете решить хотите ли вы просто выбросить его или закричать на пользователя и заставить его повторно ввести номер без каких-либо забавных комментариев).

Но тогда что? У вас просто есть строка, где вы, возможно, хотели int. К счастью, для этого есть простое решение. Мы можем рассматривать строку как источник данных потока , используя стандартный класс библиотеки std::stringstream. Мы просто создаем поток строки из строки, а затем используем его так же, как std::cin - т.е. мы можем читать из него с помощью operator>>, проверять состояние потока, чтобы увидеть, было ли чтение успешным, и т. Д.

Как отмечает sbi, всегда проверяйте, было ли чтение успешным! Если вы пытаетесь прочитать int, а поток содержит текст типа "hi mom", то (a) переменная int будет не будет изменено (поэтому, если он был неинициализирован, он все еще неинициализирован, в очень опасном состоянии), и (b) поток перейдет в состояние «сбой» и не читайте дальше, пока вы не очистите его, и (c) даже если вы очистите его, данные все равно будут там, что может вызвать бесконечный цикл, если вы не будете осторожны.

К счастью, с отдельным stringstream мы избегаем всевозможных осложнений. Если чтение не удается, то все это происходит с объектом stringstream, а не с std::cin. Операция getline всегда будет успешной на std::cin, если только пользователь явно не указывает конец файла (символ control-D в Linux или control-Z в Windows). Мы можем легко проверить, находится ли stringstream в состоянии сбоя, выполнить цикл и просто создать еще один - старый автоматически очистится.

Мы даже можем создать вспомогательную функцию, например:

template <typename T>
// Attempt to read into to_read, and return whether successful.
bool read_primitive_from_input(std::istream& input, T& to_read) {
    std::string line;
    std::getline(std::cin, line);
    std::istringstream iss(line);
    return iss >> to_read;
}

std::stringstream предоставляется заголовком стандартной библиотеки <sstream>. std::string происходит от <string>, конечно.

...