C++: поведение std::cin при несоответствии вводимого значения типу переменной

Aug 09, 2023 03:53

Читаю подглаву 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 могут быть записаны разные значения, несмотря на то, что входящий поток перешел в состояние ошибки.

Образование, Программирование, Школа

Previous post Next post
Up