Когда и зачем мне нужно использовать cin.ignore() в С++?
Я написал очень базовую программу на С++, которая попросила пользователя ввести число, а затем строку. К моему удивлению, при запуске программы он никогда не останавливался, чтобы попросить строку. Он просто пропустил это. После некоторого чтения в StackOverflow я узнал, что мне нужно добавить строку, в которой говорится:
cin.ignore(256, '\n');
перед строкой, которая получает строковый ввод. Добавив это, проблема была решена и запустила работу программы. Мой вопрос в том, почему С++ нуждается в этой строке cin.ignore()
и как я могу предсказать, когда мне нужно будет использовать cin.ignore()
?
Вот программа, которую я написал:
#include <iostream>
#include <string>
using namespace std;
int main()
{
double num;
string mystr;
cout << "Please enter a number: " << "\n";
cin >> num;
cout << "Your number is: " << num << "\n";
cin.ignore(256, '\n'); // Why do I need this line?
cout << "Please enter your name: \n";
getline (cin, mystr);
cout << "So your name is " << mystr << "?\n";
cout << "Have a nice day. \n";
}
Ответы
Ответ 1
Игнорирование - это именно то, что подразумевает название.
Он не "выбрасывает" то, что вам не нужно, он игнорирует количество символов, которые вы указываете при его вызове, вплоть до char, который вы указываете в качестве точки останова.
Он работает как с входными, так и с выходными буферами.
По существу, для операторов std::cin
, которые вы используете игнорировать перед вызовом getline
, потому что, когда пользователь вводит что-то с std::cin
, они нажимают enter и a '\n'
char попадает в cin
буфер. Затем, если вы используете getline
, он получает новую строку char вместо нужной строки. Таким образом, вы делаете std::cin.ignore(1000,'\n')
и должны очистить буфер до нужной строки. (1000 помещается туда, чтобы пропустить определенное количество символов до указанной точки прерывания, в этом случае символ \n символа новой строки.)
Ответ 2
Ты думаешь об этом неправильно. Вы каждый раз думаете логически, когда используются cin
или getline
. Ex. Сначала попросите номер, затем попросите имя. Это неправильный способ думать о cin
. Таким образом, вы сталкиваетесь с условием гонки, потому что считаете, что поток очищается каждый раз, когда вы запрашиваете ввод.
Если вы пишете свою программу исключительно для ввода, вы обнаружите проблему:
void main(void)
{
double num;
string mystr;
cin >> num;
getline(cin, mystr);
cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
}
В вышесказанном вы думаете: "Сначала получите номер". Таким образом, вы вводите 123
нажмите enter, и ваш выход будет num=123,mystr=''
. Почему это? Это потому, что в потоке вы 123\n
, а 123
анализируется в переменной num
, а \n
все еще находится в потоке. Чтение документа для функции getline
по умолчанию будет выглядеть в istream
до тех пор, пока не встретится \n
. В этом примере, поскольку \n
находится в потоке, похоже, что он "пропустил" его, но он работал правильно.
Для выполнения вышеописанного вы должны ввести 123Hello World
, который будет правильно выводить num=123,mystr='Hello World'
. Это, или вы помещаете cin.ignore
между cin
и getline
, чтобы он разбился на логические шаги, которые вы ожидаете.
Вот почему вам нужна команда ignore
. Потому что вы думаете об этом в логических шагах, а не в форме потока, чтобы вы столкнулись с состоянием гонки.
Возьмите другой пример кода, который обычно встречается в школах:
void main(void)
{
int age;
string firstName;
string lastName;
cout << "First name: ";
cin >> firstName;
cout << "Last name: ";
cin >> lastName;
cout << "Age: ";
cin >> age;
cout << "Hello " << firstName << " " << lastName << "! You are " << age << " years old!" << endl;
}
Вышеизложенное представляется логичным. Сначала спросите имя, фамилию, возраст. Итак, если вы сделали John
введите, затем Doe
введите, затем 19
введите, приложение выполняет каждый логический шаг. Если вы думаете об этом в "потоках", вы можете просто ввести John Doe 19
в вопрос "Имя:", и он тоже сработает и, похоже, пропустит оставшиеся вопросы. Чтобы вышеперечисленное работало в логических шагах, вам потребуется ignore
оставшийся поток для каждого логического разрыва в вопросах.
Не забудьте вспомнить свой ввод программы, поскольку он читает "поток", а не логически. Каждый раз, когда вы вызываете cin
, он считывается из потока. Это создает довольно ошибочное приложение, если пользователь вводит неверный ввод. Например, если вы ввели символ, где ожидается cin >> double
, приложение будет обрабатывать довольно (казалось бы) странный вывод.
Ответ 3
Если вы хотите вручную удалить определенное количество символов из входного потока.
Очень распространенный случай использования - это безопасное игнорирование символов новой строки, поскольку cin иногда оставляет символы новой строки, которые вам придется переходить, чтобы перейти к следующей строке ввода.
Короче говоря, это дает вам гибкость при обработке потока ввода.
Ответ 4
Короткий ответ
Зачем? Потому что во входном потоке остаются пробелы (возврат каретки, табуляция, пробелы, перевод строки).
Когда? Когда вы используете какую-то функцию, которая сама по себе не игнорирует начальные пробелы. Cin по умолчанию игнорирует и удаляет начальные пробелы, но getline не игнорирует ведущие пробелы самостоятельно.
Теперь подробный ответ.
Все, что вы вводите в консоль, читается из стандартного потока stdin. Когда вы вводите что-то, скажем 256 в вашем случае и нажимаете ввод, содержимое потока становится 256\n
. Теперь cin берет 256 и удаляет его из потока, а \n
все еще остается в потоке. Теперь, когда вы введете свое имя, скажем, Raddicus
, новое содержимое потока будет \nRaddicus
.
Теперь здесь идет улов. Когда вы пытаетесь прочитать строку с использованием getline, если в качестве третьего аргумента не указан какой-либо разделитель, getline по умолчанию считывает символ новой строки и удаляет символ новой строки из потока. Поэтому при вызове новой строки getline читает и отбрасывает \n
из потока, в результате чего в mystr читается пустая строка, которая выглядит как пропущенная getline (но это не так), поскольку в потоке уже была новая строка, getline не запрашивает вход, как он уже прочитал, что он должен был прочитать.
Теперь, как cin.ignore помогает здесь?
В соответствии с документацией игнорирования выписка из cplusplus.com -
istream & ignore (размер потока n = 1, int delim = EOF);
Извлекает символы из входной последовательности и отбрасывает их до тех пор, пока не будет извлечено n символов или один из них не будет равен delim.
Функция также прекращает извлечение символов, если достигнут конец файла. Если это достигается преждевременно (перед извлечением n символов или поиском разделителя), функция устанавливает флаг eofbit.
Итак, cin.ignore(256, '\n');
, игнорирует первые 256 символов или все символы, пока не встретит разделитель (здесь\n в вашем случае), в зависимости от того, что произойдет первым (здесь\n - первый символ, поэтому он игнорирует, пока не встретится \n).
Для справки: если вы точно не знаете, сколько символов пропустить, и ваша единственная цель - очистить поток, чтобы подготовиться к чтению строки, используя getline или cin, вы должны использовать cin.ignore(numeric_limits<streamsize>::max(),'\n')
.
Краткое объяснение: он игнорирует символы, равные максимальному размеру потока или до тех пор, пока не встретится '\n', в зависимости от того, что произойдет раньше.
Ответ 5
Функция игнорирования используется для пропуска (отбрасывания/выброса) символов во входном потоке. Игнорировать файл связан с файлом istream.
Рассмотрим функцию, приведенную ниже
ex: cin.ignore(120, '/n');
конкретная функция пропускает следующий 120 входных символов или пропускает символы до тех пор, пока не будет прочитан символ новой строки.
Ответ 6
Это не ответ.
Я тоже пробовал что-то подобное, но мой код не работает должным образом. Он рекурсивно зацикливается. Я использовал функцию игнорирования, но не могу ее избежать. Прикрепили фрагмент кода и снимок проблемы.
cout<<"\n\n\t\tEnter the details : \n";
for( ;ch=='y' ; )
{
cout<<"\n\t\tEnter the ID : ";
cin>>eid;
cout<<"\n\t\tEnter the Name : ";
getline(cin, ename);
cin.ignore();
cout<<"\n\t\tEnter the Gross Revenue : ";
cin>>esal;
obj.insert(eid, esal, ename);
cout<<"\n\t\t\tNew Entries ? Y/N ";
cin>>ch;
}
cout<<"\n\n\t\t\t\tPress Any Key to Continue......";
getch();
Снимок, показывающий проблему
Ответ 7
Лучше использовать scanf ("% [^\n]", str) в c++, чем cin.ignore() после cin >> statement.Чтобы сделать это сначала, вы должны включить заголовок <cstdio>.