Loop until integer input is in required range fails to work with non-digit character inputs

后端 未结 4 1318
没有蜡笔的小新
没有蜡笔的小新 2020-12-01 17:25

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

相关标签:
4条回答
  • 2020-12-01 17:54

    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.

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

    #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;
        }
    }
    
    0 讨论(0)
  • 2020-12-01 18:08

    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.

    Ur problem can be easily solved by changing your while loop. instead of checking this how about you check

    while(input!=1 || input!=2 || input!=3)
    
    0 讨论(0)
  • 2020-12-01 18:10

    Most of these answers include unnecessary complexity.

    Input validation is a perfect time to use a 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 failed cin.

    • Use cin.clear() to reset the fail flag on cin so !cin wont always evaluate false.

    cin.fail() is fine. However some would consider !cin more natural.

    from my previous post https://stackoverflow.com/a/43421325/5890809

    0 讨论(0)
  • 2020-12-01 18:18
    #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;
    }
    
    0 讨论(0)
提交回复
热议问题