Проверка ввода пользователя - это проверка состояния потока после каждого ввода. Состояние ошибки потока состоит из четырех основных состояний битовой маски goodbit (без ошибок), badbit (неисправимая ошибка), failbit (плохое преобразование / извлечение) и eofbit (конец файла) . Каждое состояние потока может быть проверено с помощью соответствующей функции-члена .good()
, .bad()
, .fail()
и .eof()
или при чтении и проверке std :: basic_ ios :: rdstate напрямую.
И .eof()
, и .bad()
не подлежат восстановлению, .fail()
требует, чтобы вы удалили все оскорбительные символы, вызывающие сбой, из потока ввода перед попыткой следующего ввода (или тот же самый ввод, вызвавший сбой, будет прочитан снова), а затем очистить состояние ошибки потока с помощью функции-члена .clear()
.
При принятии пользовательского ввода надежный подход будет * l 1055 * постоянно, требуя от пользователя предоставления правильного ввода с выдачей достаточной диагностики информировать пользователя о том, что пошло не так, и обрабатывать очистку любого failbit
из состояния потока, а также любых оскорбительных или посторонних символов из входного потока перед следующим вводом. Подход довольно прост, просто введите непрерывное l oop, запрос, проверьте состояние потока, выйдите при неисправимой ошибке, .clear()
ошибка потока на .fail()
, подтвердите ввод в нужном диапазоне и break
l oop, если все критерии удовлетворены, и, наконец, удаление всех символов до конца строки перед началом следующей итерации ввода.
Чтобы прочитать rate
, чем можно собрать, как показано ниже :
for (;;) { /* loop continually until valid input is received */
std::cout << "\nenter rate: $ " << std::flush; /* prompt/flush */
if ( !(std::cin >> rate) ) {
/* if eof() or bad() (unrecoverable) break read loop */
if (std::cin.eof() || std::cin.bad()) {
std::cerr << " user canceled or unrecoverable stream error.\n";
return 1;
}
else if (std::cin.fail()) { /* if failbit */
std::cerr << " error: invalid double input.\n";
std::cin.clear(); /* clear failbit */
}
}
else if (rate > max_rate) /* validate against max_rate */
std::cerr << " rate entered exceeds max_rate (" << max_rate << ")\n";
else /* all checks passed, good input */
break;
/* empty any extraneous character to end-of-line */
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
}
То же самое можно сделать для hours
. Вы можете написать функцию, которая обрабатывает запрос и проверку, чтобы сократить некоторые повторения в теле вашего кода, но просто включить циклы проверки для rate
и hours
вполне подойдет. Содержание и проверка являются важной частью.
Добавление короткого main()
, полный пример может быть:
#include <iostream>
#include <limits>
#define max_rate 50 /* good -- if you need a constant, #define one (or more) */
#define max_hours 80
int main (void) {
double rate, hours;
for (;;) { /* loop continually until valid input is received */
std::cout << "\nenter rate: $ " << std::flush; /* prompt/flush */
if ( !(std::cin >> rate) ) {
/* if eof() or bad() (unrecoverable) break read loop */
if (std::cin.eof() || std::cin.bad()) {
std::cerr << " user canceled or unrecoverable stream error.\n";
return 1;
}
else if (std::cin.fail()) { /* if failbit */
std::cerr << " error: invalid double input.\n";
std::cin.clear(); /* clear failbit */
}
}
else if (rate > max_rate) /* validate against max_rate */
std::cerr << " rate entered exceeds max_rate (" << max_rate << ")\n";
else /* all checks passed, good input */
break;
/* empty any extraneous character to end-of-line */
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
}
for (;;) { /* loop continually until valid input is received */
std::cout << "\nenter hours: " << std::flush; /* prompt/flush */
if ( !(std::cin >> hours) ) {
/* if eof() or bad() (unrecoverable) break read loop */
if (std::cin.eof() || std::cin.bad()) {
std::cerr << " user canceled or unrecoverable stream error.\n";
return 1;
}
else if (std::cin.fail()) { /* if failbit */
std::cerr << " error: invalid double input.\n";
std::cin.clear(); /* clear failbit */
}
}
else if (hours > max_hours) /* validate against max_hours */
std::cerr << " hours entered exceeds max_hours (" << max_hours << ")\n";
else /* all checks passed, good input */
break;
/* empty any extraneous character to end-of-line */
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
}
double pay = rate * hours;
std::cout << "\n$" << pay << '\n';
}
Пример использования / Вывод
После того, как вы написали подпрограмму ввода - go попробуйте сломать ее. Преднамеренно вводите неверный ввод и дополнительный посторонний ввод после хороших значений, чтобы убедиться, что вы обрабатываете все аспекты ввода. Минимальный прогон может быть следующим:
$ ./bin/validate_rate_hours
enter rate: $ 56 dollars
rate entered exceeds max_rate (50)
enter rate: $ I don't care I really want $50!!
error: invalid double input.
enter rate: $ 50
enter hours: 120 hours and 59 minutes and 59 seconds
hours entered exceeds max_hours (80)
enter hours: I really want 120:59:59!!
error: invalid double input.
enter hours: 80
$4000
Понимание и проверка состояний ошибок потока C ++ - ключ к написанию надежных подпрограмм ввода. Посмотрите вещи и дайте мне знать, если у вас есть вопросы.