Проблема использования Cin дважды - PullRequest
8 голосов
/ 26 марта 2010

Вот код:

string str;
cin>>str;
cout<<"first input:"<<str<<endl;
getline(cin, str);
cout<<"line input:"<<str<<endl;

В результате getline никогда не приостанавливается для пользовательского ввода, поэтому второй вывод всегда пуст.

Потратив некоторое время на это, я понял, что после первого вызова "cin >> str" кажется, что \ n все еще сохраняется в cin (используя cin.peek () для проверки), что немедленно завершает getline. Решением будет добавление еще одной строки между первым использованием и вторым: cin.ignore(numeric_limits::max(), '\n');

Однако я до сих пор не понимаю, почему после первого звонка остается «\ n»? Что на самом деле делает istream & operator >>

Ответы [ 6 ]

7 голосов
/ 26 марта 2010

\n остается во входном потоке согласно способу operator>>, определенному для std::string. std::string заполняется символами из входного потока до тех пор, пока символ пробела не будет найден (в данном случае \n), после чего заполнение прекращается, и пробел становится следующим символом во входном потоке.

Вы также можете удалить \n, позвонив cin.get() сразу после cin>>str. Однако существует много, много разных способов снятия шкур с этого конкретного кота ввода / вывода. (Возможно, хороший вопрос сам по себе?)

2 голосов
/ 26 марта 2010

Я обычно рекомендую делать только строковый ввод из std :: cin.Итак, ваш код может выглядеть примерно так:

string str;
int val;
// Read an entire line and parse an integer from it
{
    string line;
    getline(cin, line);
    istringstream iss(line);
    iss >> val;
}
cout<<"first input:"<<val<<endl;
getline(cin, str);
cout<<"line input:"<<str<<endl;

Обязательно добавьте проверку ошибок тоже.

Подход только для getline позволяет избежать необходимости думать о буферизации строк ввода,очистка ввода и т. д. Если вы что-то читаете напрямую с помощью >>, ввод не прекращается, если пользователь нажимает клавишу ввода вместо ввода требуемого, а вместо этого продолжается до тех пор, пока не будет введен токен (это поведение обычно не требуется).1006 *

2 голосов
/ 26 марта 2010

Как уже говорили другие, проблема заключается в том, что символ новой строки оставлен после первого извлечения. Одним из решений, которое я делаю, является удаление всех оставшихся символов в потоке:

std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
1 голос
/ 26 марта 2010

По умолчанию оператор вставки потока читает, пока не увидит пробел. Ваш первый вызов не возвращается, пока он не увидит пробел, символ табуляции, новую строку и т. Д. Затем необходимо использовать следующий символ, чтобы вы могли перейти к следующему.

0 голосов
/ 09 августа 2016

Также искал наиболее подходящее решение. Реализация этого оператора может вызвать проблемы. И не всегда допустимо читать всю строку или не смешивать разные типы в одной строке ввода.

Чтобы решить проблему, когда вы хотите прочитать некоторые данные из cin и не знаете, правильно ли были извлечены пробелы после последней операции ввода, вы можете сделать так:

std::string str;
std::cin >> std::ws >> str;

Но вы не можете использовать это для очистки завершающего символа новой строки после последней операции ввода из cin, чтобы не влиять на новый ввод, потому что std::ws будет использовать все пробелы и не вернет управление до тех пор, пока не будет введен первый символ, отличный от ws или EOF будет найден, поэтому нажатие Enter не завершит процесс ввода. В этом случае следует использовать

 std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );

, который является более гибким.

P.S. Если получено сообщение об ошибке с функцией max(), такой как «ожидаемый идентификатор», это может быть вызвано макросами max, определенными в некотором заголовке (например, Microsoft); это можно исправить с помощью

 #undef max
0 голосов
/ 26 марта 2010

Хорошая запись, объясняющая некоторые причины, по которым вы сталкиваетесь с этой проблемой, в основном из-за поведения типов ввода и того, что вы их смешиваете

...