Почему мы используем:
1) cin.ignore
2) cin.clear
Просто:
1) Игнорировать (извлекать и отбрасывать) значения, которые нам не нужны в потоке
2) Очистить внутреннее состояние потока. После использования cin.clear внутреннее состояние снова возвращается в Goodbit, что означает отсутствие «ошибок».
Длинная версия:
Если что-то помещено в «поток» (cin), то это должно быть взято оттуда. Под «взятым» мы подразумеваем «использованный», «удаленный», «извлеченный» из потока. Поток имеет поток. Данные текут по кину как вода по течению. Вы просто не можете остановить поток воды;)
Посмотрите на пример:
string name; //line 1
cout << "Give me your name and surname:"<<endl;//line 2
cin >> name;//line 3
int age;//line 4
cout << "Give me your age:" <<endl;//line 5
cin >> age;//line 6
Что произойдет, если пользователь ответит: «Arkadiusz Wlodarczyk» за первый вопрос?
Запустите программу, чтобы убедиться в этом.
Вы увидите на консоли «Arkadiusz», но программа не будет запрашивать у вас «возраст». Это просто закончится сразу же после печати "Arkadiusz".
А "Влодарчик" не показан. Похоже, что если он ушел (?) *
Что случилось? ; -)
Потому что между "Аркадиушем" и "Влодарчиком" есть пробел.
Символ «пробел» между именем и фамилией является для компьютера признаком того, что в потоке «input» ожидают извлечения две переменные.
Компьютер считает, что вы пытаетесь отправить на вход более одной переменной. Этот «космический» знак является знаком для него, чтобы интерпретировать его таким образом.
Таким образом, компьютер назначает «Arkadiusz» для «name» (2), и поскольку вы помещаете более одной строки в поток (вход), компьютер попытается присвоить значение «Wlodarczyk» переменной «age» (!). У пользователя не будет возможности поместить что-либо в 'cin' в строке 6, потому что эта инструкция уже выполнена (!). Зачем? Потому что в потоке еще осталось что-то. И, как я сказал ранее, поток находится в потоке, поэтому все должно быть удалено из него как можно скорее. И такая возможность появилась, когда компьютер увидел инструкцию cin >> age;
Компьютер не знает, что вы создали переменную, в которой хранится возраст кого-либо (строка 4). «возраст» - это просто ярлык. Для компьютера «возраст» можно было бы также назвать: «afsfasgfsagasggas», и это будет то же самое. Для него это просто переменная, которой он попытается присвоить "Wlodarczyk", потому что вы приказали / дали команду компьютеру сделать это в строке (6).
Это неправильно, но эй, это ты сделал это! Это твоя ошибка! Ну, может быть, пользователь, но все же ...
Хорошо, все в порядке. Но как это исправить?!
Давайте попробуем поиграть с этим примером, прежде чем мы исправим его, чтобы выучить еще несколько интересных вещей: -)
Я предпочитаю подходить так, чтобы мы понимали вещи. Исправление чего-либо без знания того, как мы это сделали, не приносит удовлетворения, не правда ли? :)
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate(); //new line is here :-)
После вызова приведенного выше кода вы заметите, что состояние вашего потока (cin) равно 4 (строка 7). Это означает, что его внутреннее состояние больше не равно goodbit. Что-то напутало. Это довольно очевидно, не так ли? Вы пытались присвоить значение типа строки ("Wlodarczyk") переменной типа int 'age'. Типы не совпадают. Пришло время сообщить, что что-то не так. И компьютер делает это, изменяя внутреннее состояние потока. Это как: «Ты, черт возьми, поправь меня, пожалуйста. Я сообщаю тебе« любезно »;-)»
Вы просто не можете больше использовать cin (поток). Он застрял. Как будто вы положили большие деревянные бревна на поток воды. Вы должны исправить это, прежде чем сможете его использовать. Данные (вода) не могут быть получены из этого потока (cin) больше, потому что журнал древесины (внутреннее состояние) не позволяет вам сделать это.
Да, так что, если есть препятствие (деревянные бревна), мы можем просто удалить его, используя специально предназначенные для этого инструменты?
Да!
внутреннее состояние cin, установленное на 4, похоже на сигнал тревоги, который воет и издает шум.
cin.clear очищает состояние до нормального (goodbit).Это как если бы ты пришел и отключил будильник.Вы просто отложите это.Вы знаете, что что-то случилось, поэтому вы говорите: «Можно прекратить шуметь, я знаю, что что-то уже не так, заткнись (очистить)».
Хорошо, давайте сделаем это!Давайте будем использовать cin.clear ().
. Вызвать приведенный ниже код с использованием «Arkadiusz Wlodarczyk» в качестве первого ввода:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl; //new line is here :-)
. После выполнения приведенного выше кода мы наверняка увидим, что состояние равно goodbit..
Отлично, так что проблема решена?
Вызвать приведенный ниже код, используя «Arkadiusz Wlodarczyk» в качестве первого ввода:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;//new line is here :-)
Даже если состояние установлено на goodbit послеВ строке 9 пользователя не запрашивается «возраст».Программа останавливается.
ПОЧЕМУ?!
О, чувак ... Вы только что отключили тревогу, как насчет бревна в воде? * Вернитесь к тексту, где мы говорили"Wlodarczyk", как якобы пропал.
Вам нужно удалить "Wlodarczyk" этот кусок дерева из ручья.Отключение будильника не решает проблему вообще.Вы только что заставили его замолчать и думаете, что проблема ушла?;)
Итак, пришло время для другого инструмента:
cin.ignore можно сравнить со специальным грузовиком с веревками, который приходит и удаляет бревна, которые застряли в потоке.Это устраняет проблему, созданную пользователем вашей программы.
Так можем ли мы использовать его даже до срабатывания будильника?
Да:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
The "Wlodarczyk""будет удален до создания шума в строке 7.
Что такое 10000 и '\ n'?
В нем говорится, что нужно удалить 10000 символов (на всякий случай), пока" \ n "не будетвстретил (ENTER).Кстати, это можно сделать лучше, используя numeric_limits, но это не тема этого ответа.
Таким образом, основная причина проблемы исчезла до того, как был сделан шум ...
Почему мытогда нужно «очистить»?
Что если бы кто-то задал вопрос «дайте мне свой возраст» в строке 6, например: «двадцать лет» вместо того, чтобы писать 20?
Types not 'снова совпадают.Компьютер пытается присвоить строку int.И начинается тревога.У вас нет шансов даже отреагировать на такую ситуацию.cin.ignore не поможет вам в таком случае.
Так что в этом случае мы должны использовать clear:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
Но следует ли очищать состояние «на всякий случай»?
Конечно, нет.
Если что-то пойдет не так (cin >> age;), инструкция сообщит вам об этом, вернув false.
Таким образом, мы можем использовать условное выражениечтобы проверить, не указал ли пользователь неверный тип в потоке
int age;
if (cin >> age) //it's gonna return false if types doesn't match
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";
Хорошо, мы можем исправить нашу первоначальную проблему, например, такую как:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
if (cin >> age)
cout << "Your age is equal to:" << endl;
else
{
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
cout << "Give me your age name as string I dare you";
cin >> age;
}
Конечно, это можно улучшитьнапример, делая то, что вы делали, используя цикл while.
БОНУС:
Возможно, вам интересно.А что, если я хочу получить имя и фамилию в одной строке от пользователя?Возможно ли использование cin, если cin интерпретирует каждое значение, разделенное пробелом, как другую переменную?
Конечно, вы можете сделать это двумя способами:
1)
string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;
cout << "Hello, " << name << " " << surname << endl;
2) или с помощью функции getline.
getline(cin, nameOfStringVariable);
и вот как это сделать:
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Второй вариант может иметь неприятные последствия, если вы используете его после использования 'cin 'перед getline.
Давайте проверим это:
a)
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Если вы введете «20» в качестве возраста, вас не спросят nameAndSurname.
Но если вы сделаете это так:
b)
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll
все хорошо.
ЧТО?!
Каждый раз, когда вы помещаете что-то на вход (поток), вы оставляете в конце белый символ ENTER ('\ n'). Вы должны каким-то образом вводить значения в консоль.Поэтому это должно произойти, если данные поступают от пользователя.
b) Характеристики cin - это то, что он игнорирует пробел, поэтому, когда вы читаете информацию из cin, символ новой строки '\ n' не имеет значения.Это игнорируется.
a) Функция getline возвращает всю строку до символа новой строки ('\ n'), а когда символ новой строки является первым, функция getline получает '\ n', и это все, что нужно. Вы извлекаете символ новой строки, который был оставлен в потоке пользователем, который поставил «20» в потоке в строке 3.
Так что для исправления это всегда вызывать cin.ignore (); каждый раз, когда вы используете cin для получения любого значения, если вы когда-либо собираетесь использовать getline () внутри вашей программы.
Таким образом, правильный код будет:
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, '\n')
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Надеюсь, вам понятнее потоки.
Ха, пожалуйста, помолчи! : -)