C++ 循环直到整数输入在所需范围内无法处理非数字字符输入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13212043/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loop until integer input is in required range fails to work with non-digit character inputs
提问by Rick_Sch
I'm having a problem with what should be incredibly simple code. I want to take in an integer between 1 and 3 with error checking. It works fine for checking for numbers that are too large or too small, but when a alpha/number combination is entered, it gets stuck in an infinite loop. Suggestions?
我对应该非常简单的代码有疑问。我想通过错误检查接收 1 到 3 之间的整数。它可以很好地检查过大或过小的数字,但是当输入字母/数字组合时,它会陷入无限循环。建议?
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
int input;
cout << "\nPlease enter a number from 1 to 3:" << endl;
cout << "-> ";
cin >> input;
while(input< 1 || input> 3){
cout << "\n---------------------------------------" << endl;
cout << "\n[!] The number you entered was invalid." << endl;
cout << "\nPlease re-enter a number from 1 to 3" << endl;
cout << "-> ";
cin >> input;
}
cout << "You chose " << input << endl;
}
回答by Martin York
The problem is that:
问题在于:
cin >> input;
Will cause the bad bit to be set when you try and read a non numeric value. After that happens any attempt to use the operator>>
is silently ignored.
当您尝试读取非数值时,会导致设置坏位。在此之后,任何使用 的尝试都会operator>>
被默默忽略。
So the way to correct for this is to test if the stream is in a good state and if not then reset the state flags and try and read again. But note that the bad input (that caused the problem) is still on the input so you need to make sure you throw it away as well.
因此,纠正此问题的方法是测试流是否处于良好状态,如果不是,则重置状态标志并再次尝试读取。但请注意,错误的输入(导致问题的)仍在输入中,因此您需要确保也将其丢弃。
if (cin >> input)
{
// It worked (input is now in a good state)
}
else
{
// input is in a bad state.
// So first clear the state.
cin.clear();
// Now you must get rid of the bad input.
// Personally I would just ignore the rest of the line
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// now that you have reset the stream you can go back and try and read again.
}
To prevent it getting stuck (which is caused by the bad bit being set) read into a string then use a string stream to parse user input. I also prefer this method (for user interactive input) as it allows for easier combination of different styles of reading (ie combining operator>>
and std::getline()
as you can use these on the stringstream).
为了防止它卡住(这是由设置的坏位引起的)读入一个字符串,然后使用一个字符串流来解析用户输入。我也更喜欢这种方法(用于用户交互式输入),因为它允许更容易地组合不同的阅读风格(即组合operator>>
,std::getline()
因为您可以在字符串流上使用这些)。
#include <iostream>
#include <sstream>
#include <string>
// using namespace std;
// Try to stop using this.
// For anything other than a toy program it becomes a problem.
int main(int argc, char *argv[])
{
int input;
std::string line;
while(std::getline(std::cin, line)) // read a line at a time for parsing.
{
std::stringstream linestream(line);
if (!(linestream >> input))
{
// input was not a number
// Error message and try again
continue;
}
if ((input < 1) || (input > 3))
{
// Error out of range
// Message and try again
continue;
}
char errorTest;
if (linestream >> errorTest)
{
// There was extra stuff on the same line.
// ie sobody typed 2x<enter>
// Error Message;
continue;
}
// it worked perfectly.
// The value is now in input.
// So break out of the loop.
break;
}
}
回答by pokey909
#include <iostream>
#include <string>
using namespace std;
int validatedInput(int min = 1, int max = 3)
{
while(true)
{
cout << "Enter a number: ";
string s;
getline(cin,s);
char *endp = 0;
int ret = strtol(s.c_str(),&endp,10);
if(endp!=s.c_str() && !*endp && ret >= min && ret <= max)
return ret;
cout << "Invalid input. Allowed range: " << min << "-" << max <<endl;
}
}
int main(int argc, char *argv[])
{
int val = validatedInput();
cout << "You entered " << val <<endl;
return 0;
}
回答by Shan L
Most of these answers include unnecessary complexity.
大多数这些答案都包含不必要的复杂性。
Input validation is a perfect time to use a do-while
输入验证是使用 do-while 的最佳时机
do{
cout << "\nPlease enter a number from 1 to 3:" << endl;
cout << "-> ";
if(!cin){
cout << "Invalid input"
cin.clear()
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}while(!(cin >> input))
Use
numeric_limits<streamsize>::max()
to completely clear the buffer after a failedcin
.Use
cin.clear()
to reset the fail flag oncin
so!cin
wont always evaluate false.
用于
numeric_limits<streamsize>::max()
在失败后完全清除缓冲区cin
。使用
cin.clear()
重置的失败标志cin
,以便!cin
不会永远评估假。
cin.fail()
is fine. However some would consider !cin
more natural.
cin.fail()
很好。然而,有些人会认为!cin
更自然。
from my previous post https://stackoverflow.com/a/43421325/5890809
回答by RDismyname
You declared input as int but when you write an alphanumeric character to input it will try to implicitly convert it into integer. But you error checking does not account for this.
您将 input 声明为 int 但是当您编写一个字母数字字符来输入时,它会尝试将其隐式转换为整数。但是您的错误检查并没有考虑到这一点。
Ur problem can be easily solved by changing your while loop. instead of checking this how about you check
你的问题可以通过改变你的while循环轻松解决。而不是检查这个你如何检查
while(input!=1 || input!=2 || input!=3)