Когда и почему мне нужно использовать cin.ignore() в C++?
Я написал очень простую программу на C++, которая попросила пользователя ввести число, а затем строку. К моему удивлению, при запуске программы она никогда не переставала спрашивать строку. Он просто пропустил это. После прочтения Stackru я обнаружил, что мне нужно добавить строку с надписью:
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";
}
5 ответов
Игнорировать это именно то, что подразумевает название.
Вместо этого он не "выбрасывает" то, что вам не нужно, он игнорирует количество символов, которое вы указываете при вызове, вплоть до символа, который вы указываете в качестве точки останова.
Работает как с входным, так и с выходным буфером.
По сути, для std::cin
заявления, которые вы используете игнорировать, прежде чем сделать getline
вызов, потому что, когда пользователь вводит что-то с std::cin
, они нажали войти и '\n'
полукокса попадает в cin
буфер. Тогда, если вы используете getline
, он получает символ новой строки вместо строки, которую вы хотите. Итак, вы делаете std::cin.ignore(1000,'\n')
и это должно очистить буфер до строки, которую вы хотите. (1000 помещается туда, чтобы пропустить определенное количество символов до указанной точки останова, в данном случае, символа \n новой строки.)
Вы думаете об этом неправильно. Вы мыслите логическими шагами каждый раз cin
или же getline
используется. Ex. Сначала спросите номер, затем спросите имя. Это неправильный способ думать о cin
, Таким образом, вы попадаете в состояние гонки, потому что вы предполагаете, что поток очищается каждый раз, когда вы запрашиваете ввод.
Если вы напишите свою программу исключительно для ввода, вы найдете проблему:
void main(void)
{
double num;
string mystr;
cin >> num;
getline(cin, mystr);
cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
}
Выше вы думаете:"сначала получите номер". Итак, вы вводите 123
нажмите ввод, и ваш вывод будет 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
ожидается, что приложение выдаст довольно (на первый взгляд) причудливый вывод.
Короткий ответ
Зачем? Потому что во входном потоке остаются пробелы (возврат каретки, табуляция, пробелы, перевод строки).
Когда? Когда вы используете какую-то функцию, которая сама по себе не игнорирует начальные пробелы. 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', в зависимости от того, что произойдет раньше.
Когда вы хотите выбросить определенное количество символов из потока ввода вручную.
Очень распространенный вариант использования - это использование для безопасного игнорирования символов новой строки, поскольку cin иногда оставляет символы новой строки, которые вам придется перейти, чтобы перейти к следующей строке ввода.
Короче говоря, это дает вам гибкость при обработке потокового ввода.
Функция игнорирования используется для пропуска (отбрасывания / отбрасывания) символов во входном потоке. Игнорировать файл связан с файлом istream. Рассмотрим функцию ниже ex: cin.ignore(120,'/n'); конкретная функция пропускает следующие 120 вводимых символов или пропускает символы, пока символ новой строки не будет прочитан.
Как правильно указывали многие другие пользователи. Это потому, что может быть пробел или символ новой строки.
Рассмотрим следующий код, он удаляет все повторяющиеся символы из данной строки.
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
cin>>t;
cin.ignore(); //Notice that this cin.ignore() is really crucial for any extra whitespace or newline character
while(t--){
vector<int> v(256,0);
string s;
getline(cin,s);
string s2;
for(int i=0;i<s.size();i++){
if (v[s[i]]) continue;
else{
s2.push_back(s[i]);
v[s[i]]++;
}
}
cout<<s2<<endl;
}
return 0;
}
Итак, вы понимаете, что он проигнорирует эти нежелательные входные данные и выполнит свою работу.
Лучше использовать scanf(" %[^\n]",str) в C++, чем cin.ignore() после оператора cin>>. Для этого сначала нужно включить заголовок