Search code examples
c++loopsvalidationistream

How do I create a loop that lets the user re-enter their answer when a cin.fail() occurs?


This small segment of my program seems to cause some problems:

cout << "Would you like to change the values? Type 1 if yes or 2 if no." << endl << "You can also reverse the original vector above by typing 3. \n Answer:  ";
    cin >> yesorno;

    while (yesorno != 1 && yesorno != 2 && yesorno != 3 || cin.fail() )
        {           
        cout << "\n Sorry, didn't catch that. Try again: ";
        cin >> yesorno;
        }

The loop works fine for all valid integers as far as I know, but when an unvalid value gets declared to yesorno the loop freaks out. For example, if I input the letter A, the loop goes on for infinity. I guess what I'm asking is, how do I make it so that the user gets unlimited amounts of chances to input a valid value? I'm pretty new to C++ btw so I am not familiar with all different kinds of public member functions etc.. I've tried cin.clear() but didn't have much success


Solution

  • When you run into error in reading input data, you may use cin.clear() to clear the state of the stream and follow it with a call to cin.ignore() to ignore the rest of the line.

    while ( (yesorno != 1 && yesorno != 2 && yesorno != 3) || cin.fail() )
    {           
       cout << "\n Sorry, didn't catch that. Try again: ";
       if ( cin.fail() )
       {
          cin.clear();
          cin.input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
       }
    
       cin >> yesorno;
    }
    

    Another approach, that I prefer, is to read the input line by line and process each line independently.

    std::string line;
    while ( getline(cin, line) )
    {
       std::istringstr str(line);
       if ( !(str >> yesorno) || (yesorno != 1 && yesorno != 2 && yesorno != 3) )
       {
          cout << "\n Sorry, didn't catch that. Try again: ";
          continue;
       }
       else
       {
          // Got good input. Break out of the loop.
          break;
       }
    }