假设我们有一个菜单向用户提供了一些选项:
Welcome:
1) Do something
2) Do something else
3) Do something cool
4) Quit
用户可以按1 - 4然后按回车键。程序执行此操作,然后将菜单返回给用户。无效选项应该只显示菜单。
我有以下main()
方法:
int main()
{
while (true)
switch (menu())
{
case 1:
doSomething();
break;
case 2:
doSomethingElse();
break;
case 3:
doSomethingCool();
break;
case 4:
return 0;
default:
continue;
}
}
以及menu()
:
int menu()
{
cout << "Welcome:" << endl
<< "1: Do something" << endl
<< "2: Do something else" << endl
<< "3: Do something cool" << endl
<< "4: Quit" << endl;
int result = 0;
scanf("%d", &result);
return result;
}
输入数字类型效果很好。输入1 - 4会使程序执行所需的操作,然后再次显示菜单。输入此范围之外的数字(例如-1或12)将再次按预期显示菜单。
但是,输入“q”之类的内容只会导致菜单无限次地反复显示,甚至无法停止获取用户输入。
我不明白这是怎么发生的。显然,正在调用menu()
,因为菜单会一遍又一遍地显示,但是scanf()
是menu()
的一部分,所以我不明白程序是如何进入此错误状态的不会提示用户输入。
我最初有cin >> result
做了完全相同的事情。
修改:似乎有related question,但原始source code已从pastebin中消失,其中一个答案链接到article,显然曾经解释过为什么会这样,但现在已成为一个死链接。也许有人可以回复为什么会发生这种情况而不是链接? :)
修改:使用this example,以下是我解决问题的方法:
int getNumericalInput()
{
string input = "";
int result;
while (true)
{
getline(cin, input);
stringstream sStr(input);
if (sStr >> result)
return result;
cout << "Invalid Input. Try again: ";
}
}
我只是替换了
int result = 0;
scanf("%d", &result);
与
int result = getNumericalInput();
答案 0 :(得分:6)
当您尝试将非数字输入转换为数字时,它会失败并且(重要部分)将该数据保留在输入缓冲区中,因此下次您尝试读取int时,它仍然在那里等待,并且再次失败 - 再一次,永远失败。
有两种基本方法可以避免这种情况。我更喜欢的是读取一串数据,然后从中转换为数字并采取适当的操作。通常,您将使用std::getline
读取直到新行的所有数据,然后尝试转换它。因为它会读取正在等待的任何数据,所以你永远不会把垃圾“卡在”输入中。
替代方案是(特别是如果转换失败)使用std::ignore
从输入读取数据(通常)到下一个换行符。
答案 1 :(得分:4)
1)对自己说1000次,或直到你入睡:
如果不检查返回值,我将永远不会使用I / O函数。
2)重复上述50次。
3)重新阅读您的代码:您是否正在检查scanf
的结果?当scanf
无法将输入转换为所需格式时会发生什么?如果您不了解这些信息,您将如何学习? (脑海中浮现出四个字母。)
我还会质疑为什么你使用scanf
而不是更合适的iostreams操作,但这会遇到完全相同的问题。
答案 2 :(得分:1)
您需要验证读取是否成功。提示:它没有。在读取之后,请确保您已成功阅读输入:
if (std::cin >> result) { ... }
if (scanf("%d", result) == 1) { ... }
在C ++中,失败的状态是粘性的并且保持不变直到它被clear()
编辑。只要流处于失败状态,它就不会做任何有用的事情。在任何一种情况下,您都想要ignore()
坏人或fgetc()
。请注意,失败可能是由于到达了流的末尾,在这种情况下设置了eof()
或者分别为iostream或stdio返回了EOF
。