C++ cin.fail() 执行并移动到下一行,即使输入是另一种数据类型
C++ cin.fail() executes and moves to next line even though input is of another data type
我正在使用 get.fail() 检查输入中是否有任何字符,如果有我想给用户重新输入的机会。但是,无论如何,只要输入前面有一个整数,程序似乎仍然会接受用户输入。说 w1
和 1w
,程序会告诉用户它只接受整数,而后者接受输入并移到下一行,这会导致另一个问题。
void userChoice(int input){
switch(input)
{
case 1:
insert();
break;
case 2:
display();
break;
case 3:
update_data();
break;
case 4:
delete_position();
break;
case 5:
cout<<"Thank you for using the program\n";
exit(0);
break;
case 6:
tellSize();
break;
default:
cout<<"Not an option\n";
cin>>input;
while(cin.fail())
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cin>>input;
break;
}
userChoice(input);
}
}
参考上面的代码,假设我输入1w
。该程序仍将执行情况 1,就好像没有任何问题一样,然后 w
以某种方式传递给 insert()
函数,这不是我想要的。我希望程序让用户重新输入输入,无论它是 1w
还是 w1
,简而言之,如果有一个字符,我不希望程序移到下一行一个整数输入。
tl;博士:
为什么下面的代码在 cin 为 1w
时仍然执行,它不应该打印 "Enter number only" 因为那里有一个字符吗?
编辑:这是我制作的一个快速程序,为了重现我面临的错误,我首先输入 1h
这是我面临的第一个错误,为什么当有字符时程序仍在执行h
在输入中?之后在第二个输入中,我输入 2w
并且程序打印出 2
,程序是否应该循环 while 循环,因为输入中有一个字符 w
?
#include<iostream>
#include<iomanip>
#include<limits>
using namespace std;
void option_1()
{
int amount_input;
cout<<"Enter the amount of cake"<<endl;
cin>>amount_input;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"Enter number only\n";
cin>>amount_input;
}
cout<<amount_input;
}
void options(int input)
{
bool fail;
switch(input)
{
case 1:
option_1();
break;
default:
cout<<"Not an option"<<endl;
cin>>input;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin>>input;
break;
}
options(input);
}
}
void menu(){
int user_input;
cout<<"Enter 1 to print something\n";
cin>>user_input;
options(user_input);
}
int main(){
menu();
}
根据您的评论,您似乎只希望 整数输入 ,并且不想允许在整数后输入其他字符,例如 1w
,即使 1
将被转换为 int
,同时留下 w
未读,以便在您调用 .clear()
后被 .ignore(...)
删除。 (如上所述,您现在对 .clear()
和 .ignore(...)
的使用是正确的。
如果这是您的意图,您需要一种方法来检查用户输入的整数后是否还有其他内容。如果实际上什么都不存在,要以 non-blocking 的方式做到这一点,您有几个选择。 (例如,您可以 .peek()
在下一个字符处——但您只能得到一个,或者您可以使用 line-oriented 输入方法) line-oriented 方法允许您将整行用户输入读入 string
,然后提取整数值并检查输入行中是否包含任何其他内容。
最直接的方法是从用 getline()
读取的数据行创建一个 std::basic_stringstream。这种方法消耗了整行用户输入,并为您提供了从该行中提取您可能需要的任何信息所需的所有工具。它还以不影响任何后续用户输入的方式执行此操作。
虽然我建议您将 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);
}
根据上面的讨论,评论应该是 self-explanatory,但如果您有任何问题,请告诉我。将函数与其余代码一起使用(并注释未使用的// bool fail;
),您可以测试它是否满足您的要求,例如
例子Use/Output
$ ./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()
函数现在将正确地捕获由用户按 Ctrl+d(或 Ctrl+z on windows) 取消输入并正常退出。
我正在使用 get.fail() 检查输入中是否有任何字符,如果有我想给用户重新输入的机会。但是,无论如何,只要输入前面有一个整数,程序似乎仍然会接受用户输入。说 w1
和 1w
,程序会告诉用户它只接受整数,而后者接受输入并移到下一行,这会导致另一个问题。
void userChoice(int input){
switch(input)
{
case 1:
insert();
break;
case 2:
display();
break;
case 3:
update_data();
break;
case 4:
delete_position();
break;
case 5:
cout<<"Thank you for using the program\n";
exit(0);
break;
case 6:
tellSize();
break;
default:
cout<<"Not an option\n";
cin>>input;
while(cin.fail())
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cin>>input;
break;
}
userChoice(input);
}
}
参考上面的代码,假设我输入1w
。该程序仍将执行情况 1,就好像没有任何问题一样,然后 w
以某种方式传递给 insert()
函数,这不是我想要的。我希望程序让用户重新输入输入,无论它是 1w
还是 w1
,简而言之,如果有一个字符,我不希望程序移到下一行一个整数输入。
tl;博士:
为什么下面的代码在 cin 为 1w
时仍然执行,它不应该打印 "Enter number only" 因为那里有一个字符吗?
编辑:这是我制作的一个快速程序,为了重现我面临的错误,我首先输入 1h
这是我面临的第一个错误,为什么当有字符时程序仍在执行h
在输入中?之后在第二个输入中,我输入 2w
并且程序打印出 2
,程序是否应该循环 while 循环,因为输入中有一个字符 w
?
#include<iostream>
#include<iomanip>
#include<limits>
using namespace std;
void option_1()
{
int amount_input;
cout<<"Enter the amount of cake"<<endl;
cin>>amount_input;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout<<"Enter number only\n";
cin>>amount_input;
}
cout<<amount_input;
}
void options(int input)
{
bool fail;
switch(input)
{
case 1:
option_1();
break;
default:
cout<<"Not an option"<<endl;
cin>>input;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin>>input;
break;
}
options(input);
}
}
void menu(){
int user_input;
cout<<"Enter 1 to print something\n";
cin>>user_input;
options(user_input);
}
int main(){
menu();
}
根据您的评论,您似乎只希望 整数输入 ,并且不想允许在整数后输入其他字符,例如 1w
,即使 1
将被转换为 int
,同时留下 w
未读,以便在您调用 .clear()
后被 .ignore(...)
删除。 (如上所述,您现在对 .clear()
和 .ignore(...)
的使用是正确的。
如果这是您的意图,您需要一种方法来检查用户输入的整数后是否还有其他内容。如果实际上什么都不存在,要以 non-blocking 的方式做到这一点,您有几个选择。 (例如,您可以 .peek()
在下一个字符处——但您只能得到一个,或者您可以使用 line-oriented 输入方法) line-oriented 方法允许您将整行用户输入读入 string
,然后提取整数值并检查输入行中是否包含任何其他内容。
最直接的方法是从用 getline()
读取的数据行创建一个 std::basic_stringstream。这种方法消耗了整行用户输入,并为您提供了从该行中提取您可能需要的任何信息所需的所有工具。它还以不影响任何后续用户输入的方式执行此操作。
虽然我建议您将 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);
}
根据上面的讨论,评论应该是 self-explanatory,但如果您有任何问题,请告诉我。将函数与其余代码一起使用(并注释未使用的// bool fail;
),您可以测试它是否满足您的要求,例如
例子Use/Output
$ ./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()
函数现在将正确地捕获由用户按 Ctrl+d(或 Ctrl+z on windows) 取消输入并正常退出。