Из ваших комментариев кажется, что вы хотите целочисленный ввод исключительно и не хотите разрешать ввод дополнительного символа после целого числа, такого как 1w
, даже если 1
будет преобразовано в int
оставляя w
непрочитанным, чтобы быть удаленным .ignore(...)
после вашего звонка на .clear()
.(как уже упоминалось выше, вы используете .clear()
и .ignore(...)
теперь правильно.
Если это ваше намерение, вам нужен способ проверить, есть ли что-нибудь еще после целочисленного ввода пользователем.Чтобы сделать это неблокирующим способом, если на самом деле ничего не существует, у вас есть несколько вариантов (например, вы можете .peek()
на следующем символе - но вы получите только один, или вы можете использовать line-ориентированный подход ввода) линейный подход позволяет вам читать всю строку ввода пользователя в string
, а затем извлекать целочисленное значение и проверять, есть ли в строке что-либо еще
Самый простой способ - создать std :: basic_stringstream из строки данных, считанной с getline()
. Этот подход использует всю строку пользовательского ввода ипредоставляет вам все инструменты, необходимые для извлечения любой необходимой вам информации из линии, а также делает это таким образом, чтобы не влиять ни на один из ваших последующих пользовательских вводов.
Хотя я бы порекомендовал вам объединить функции void menu()
и void options(int input)
, чтобы у вас просто была одна функция для обработки ввода для вашего меню - нет ничего плохого в том, чтобы разбить ее на две части, кроме возможностинесколько строк кода дублируются.Ниже приведено лишь предложение о том, как обрабатывать вашу функцию menu()
, чтобы разрешить только целочисленный ввод.Вы можете адаптировать его к остальной части вашего кода.
Вам понадобится несколько дополнительных включений:
#include <sstream>
#include <string>
Я бы также #define
первый и последний приемлемые пункты меню, чтобы выэти константы должны быть доступны в вашем коде в месте, которое можно легко изменить при добавлении в меню, например,
#define MENUFIRST 1 /* first valid entry */
#define MENULAST 1 /* last valid entry */
( примечание: , что позволит вводить только 1
в качестве действительного пункта меню)
Чтобы ограничить вашу функцию menu()
с использованием подхода, описанного выше, вы можете сделать:
void menu(){
int user_input = 0;
string line, unwanted;
for (;;) { /* loop continually until valid input received */
cout << "\nEnter 1 to print something: ";
if (!getline (cin, line)) { /* read an entire line at a time */
cerr << "(user canceled or unrecoverable stream error)\n";
return;
}
stringstream ss (line); /* create a stringstream from line */
if (!(ss >> user_input)) { /* test if valid integer read */
/* test eof() or bad() */
if (ss.eof() || ss.bad()) /* if not, did user cancel or err */
cerr << "(empty-input or unreconverable error)\n";
else if (ss.fail()) /* if failbit - wasn't an int */
cerr << "error: invalid integer input.\n";
}
else if (ss >> unwanted) { /* are there unwanted chars? */
cerr << "error: additional characters following user_input.\n";
user_input = 0; /* reset user_input zero */
} /* was int outside MENUFIRST-to-MENULAST? */
else if (user_input < MENUFIRST || MENULAST < user_input)
cerr << "error: integer not a valid menu selection.\n";
else /* valid input!, break read loop */
break;
}
options(user_input);
}
Комментарии должны быть самоочевидными, учитывая обсуждение выше,но дайте мне знать, если у вас есть вопросы.Используя функцию с остальным кодом (и комментируя неиспользованный // bool fail;
), вы можете проверить, соответствует ли он вашим требованиям, например,
Пример использования / Вывод
$ ./bin/menu_int
Enter 1 to print something: w1
error: invalid integer input.
Enter 1 to print something: $#%&^#&$ (cat steps on keyboard) !#$%%^%*()
error: invalid integer input.
Enter 1 to print something: 1w
error: additional characters following user_input.
Enter 1 to print something: -1
error: integer not a valid menu selection.
Enter 1 to print something: 24
error: integer not a valid menu selection.
Enter 1 to print something: 1
Enter the amount of cake
3
3
Также обратите внимание, что ваша menu()
функция теперь будет правильно перехватывать руководство EOF
, сгенерированное пользователем, нажимающим Ctrl + d (или Ctrl + z на окнах) дляотменить ввод и выйти изящно.