循环直到整数输入在所需范围内,否则不能与非数字字符输入一起使用

问题描述 投票:5回答:4

我对本应非常简单的代码有疑问。我想接受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;
}
c++ error-handling integer infinite-loop
4个回答
8
投票

问题是:

cin >> input;

当您尝试读取非数字值时,将导致设置错误的位。在此之后,任何使用operator>>的尝试都会被忽略。

因此,解决此问题的方法是测试流是否处于良好状态,如果不是,则重置状态标志并尝试再次读取。但是请注意,错误输入(导致问题的原因)仍然在输入上,因此您需要确保也将其丢弃。

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.
}

为了防止它卡住(这是由于设置了错误的位造成的),然后将其读入字符串,然后使用字符串流来解析用户输入。我也更喜欢这种方法(用于用户交互式输入),因为它可以更轻松地组合不同的阅读样式(即,可以在字符串流中使用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;
    }
}

2
投票
#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;
}

1
投票

这些答案大多数都包含不必要的复杂性。

输入验证是使用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))
  • 使用numeric_limits<streamsize>::max()完全清除cin失败后的缓冲区。

  • 使用cin.clear()重置cin上的失败标志,因此!cin不会总是评估为假。

cin.fail()可以。但是,有些人会认为!cin更自然。

来自我之前的文章https://stackoverflow.com/a/43421325/5890809


0
投票

您将输入声明为int,但是当您输入字母数字字符进行输入时,它将尝试将其隐式转换为整数。但是您进行错误检查不能解决这个问题。

您的问题可以通过更改while循环轻松解决。而不是检查您的检查方式

while(input!=1 || input!=2 || input!=3)
© www.soinside.com 2019 - 2024. All rights reserved.