Читаю подглаву 4.10 «
Introduction to if statements» (введение в ветвления if) сайта-учебника «
LearnCpp.com».
Там в примерах встречаются фрагменты, похожие на следующее:
#include
int main()
{
std::cout << "Введите целое число: ";
int x{ 1 };
std::cin >> x;
std::cout << x << '\n';
return 0;
}
К этому моменту автор учебника еще не успел рассказать, как управляться с ошибками при получении ввода от пользователя через std::cin (про это в учебнике
будет рассказано позже).
Понятно, что автор подобного исходного кода ожидает, что пользователь будет вводить только целые числа. Примеры в этой подглаве учебника используются для демонстрации работы с ветвлениями if, а не для демонстрации правильной обработки ошибок при получении ввода через std::cin. Но вопросы, всё же, возникают. Поэтому я решил по этому поводу сделать несколько коротких пояснений в этом посте. Эти пояснения, конечно, не закрывают вопрос полностью, а только дают примерное представление о том, как работает программа в случаях, когда пользователь совершает незапланированный автором программы ввод.
Ввод букв английского алфавита вместо целого числа
Пример результата работы приведенной выше программы:
Введите целое число: word
0
Данный случай касается только ввода букв английского алфавита. К примеру, ввод букв русского алфавита - это отдельный случай, который я в этом посте рассматривать не буду.
Посмотрим, что происходит с состоянием входящего потока:
#include
int main()
{
/* отладка */ std::cout << "Состояние cin: " << std::cin.good() << '\n';
std::cout << "Введите целое число: ";
int x{ 1 };
std::cin >> x;
/* отладка */ std::cout << "Состояние cin: " << std::cin.good() << '\n';
std::cout << x << '\n';
return 0;
}
Результат работы этой программы:
Состояние cin: 1
Введите целое число: word
Состояние cin: 0
0
В общем, это основы, это я понимал и ранее: в случае, когда из входящего потока не может быть считано значение в указанную переменную, в соответствующем бите состояния входящего потока делается отметка об ошибке (дальнейший ввод становится невозможен, пока состояние не будет приведено к первоначальному значению, показывающему, что всё в порядке). В данном случае я проверяю состояние входящего потока с помощью метода
good объекта std::cin.
Однако, ранее от меня ускользала такая тонкость: несмотря на то, что произошла ошибка, в переменную x всё же было записано некое значение! (Я думал, что если происходит ошибка, то в переменную x ничего не должно быть записано, переменная должна остаться без изменений. Но я ошибался.) Это видно из того, что до ввода переменная x была инициализирована значением 1, а после ввода букв в переменной x оказалось значение 0.
Об этом сказано в известном справочнике по языку C++, в статье про
оператор извлечения, цитата:
If extraction fails (e.g. if a letter was entered where a digit is expected), zero is written to value and failbit is set.
Ввод числа, не попадающего в диапазон типа переменной
Отмечу, что ввод через std::cin в случае ошибки срабатывает по-разному. В рассмотренном выше случае в переменную было записано число 0. В других случаях в переменную может быть записано другое значение. Два примера результатов работы вышеприведенной программы:
Состояние cin: 1
Введите целое число: 3000000000
Состояние cin: 0
2147483647
Состояние cin: 1
Введите целое число: -3000000000
Состояние cin: 0
-2147483648
Переменная x, в которую должно записаться вводимое пользователем значение, имеет тип int. На моем компьютере тип int имеет размер в 4 байта, следовательно диапазон воможных значений будет следующим: -2'147'483'648..2'147'483'647. Как видно из примеров выше, при вводе значения, выходящего за пределы диапазона типа переменной, в переменную будет записано ближайшее значение, входящее в диапазон. И это несмотря на то, что входящий поток перешел в состояние ошибки.
Об этом тоже сказано в процитированной выше статье справочника по языку C++.
Я привел только несколько случаев такого поведения, но их, понятно, гораздо больше. И в каждом из случаев в переменную x могут быть записаны разные значения, несмотря на то, что входящий поток перешел в состояние ошибки.