Существует несколько способов структурировать различные тесты, но при вводе с помощью cin
(или, как правило, с любой функцией ввода), вы должны учитывать любые символы во входном буфере, которые остаются непрочитанными.С cin
у вас есть три условия, которые вы должны проверить:
.eof()
(eofbit
).Либо был достигнут конец ввода, либо пользователь вручную сгенерировал EOF
, нажав Ctrl + d (или Ctrl + z при повороте, но см .: CTRL +Z не генерирует EOF в Windows 10 );
.bad()
(badbit
).Произошла неисправимая ошибка потока;и
.fail()
(failbit
).Произошел соответствующий или другой исправимый сбой.Когда происходит сбой , ввод прекращается и никакие дополнительные символы не извлекаются из буфера ввода .
(вы можете объединить 1 и 2 в один тест, когда ввод законченв этот момент)
С failbit
вы должны сделать две вещи.(1) вы должны очистить состояние ошибки потока, вызвав cin.clear()
, и (2) вы должны обработать любые символы, которые остаются непрочитанными во входном буфере.Обычно это выполняется путем включения <limits>
и вызова:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
(который удалит до INT_MAX
символов из входного буфера, останавливаясь при обнаружении разделителя ('\n'
здесь))
Короткий пример, который повторяется до тех пор, пока пользователь не введет действительное целое число , может быть:
#include <iostream>
#include <limits>
using namespace std;
int main (void) {
int x = 0;
while (1) /* loop continually until valid input received */
{
cout << "\nenter an integer: ";
if (! (cin >> x) ) { /* check stream state */
/* if eof() or bad() break read loop */
if (cin.eof() || cin.bad()) {
cerr << "(user canceled or unreconverable error)\n";
return 1;
}
else if (cin.fail()) { /* if failbit */
cerr << "error: invalid input.\n";
cin.clear(); /* clear failbit */
/* extract any characters that remain unread */
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
else { /* on succesful read of int */
/* extract any characters that remain unread */
cin.ignore(numeric_limits<streamsize>::max(), '\n');
break; /* then break read loop */
}
}
cout << "integer: " << x << '\n';
}
(как упоминалось в начале, вы можете структурировать множество тестовдругими способами, если вы охватите все три условия.)
Кроме того, вы можете явно проверить бит потока, вызвав rdstate()
вместо тестирования с .fail()
и т. д., например
if (std::cin.rdstate() == std::ios_base::failbit)
Пример использования / Вывод
$ ./bin/cin_validate_int
enter an integer: no
error: invalid input.
enter an integer: "an integer"
error: invalid input.
enter an integer: abc 123
error: invalid input.
enter an integer: 123
integer: 123
Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.