-1

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

Christophe
  • 68,716
  • 7
  • 72
  • 138
Outliggare
  • 19
  • 2
  • 1
    [`cin.clear()`](https://en.cppreference.com/w/cpp/io/basic_ios/clear) and [`cin.ignore()`](https://en.cppreference.com/w/cpp/io/basic_istream/ignore) are your friends in such cases. – R Sahu Mar 27 '20 at 16:22
  • You need to clear the fail bit, and probably a good idea to ignore too – ChrisMM Mar 27 '20 at 16:22
  • Does this answer your question? [How to check if input is numeric in C++](https://stackoverflow.com/questions/5655142/how-to-check-if-input-is-numeric-in-c) – Object object Mar 27 '20 at 16:28
  • **It might be operating system specific**. On Linux specifically consider using [GNU readline](http://man7.org/linux/man-pages/man3/readline.3.html) or [ncurses](https://en.wikipedia.org/wiki/Ncurses) if your standard input is a terminal (which you could check using [isatty(3)](http://man7.org/linux/man-pages/man3/isatty.3.html) on `STDIN_FILENO`...) with [sscanf](http://man7.org/linux/man-pages/man3/sscanf.3.html) and `%n` – Basile Starynkevitch Mar 27 '20 at 16:37

2 Answers2

2

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;
   }
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

When the fail bit gets set, you need to clear it before continuing.

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