7

I'm writing a program where I get an integer input from the user with cin>>iUserSel;. If the user puts in a letter, the program goes to an infinite loop. I tried to prevent that with the code below, but the program goes to an infinite loop and prints out "Wrong! Enter a #!". How can I fix my program?

cin>>iUserSel;
while (iValid == 1)
{
        if (cin.fail())
        {
                cin.ignore();
                cout<<"Wrong! Enter a #!"<<endl;
                cin>>iUserSel;
        }//closes if
        else
                iValid = 0;
}//closes while

I found some information on this at Correct way to use cin.fail() and C++ cin.fail() question , but I didn't understand how to use them to fix my issue.

Community
  • 1
  • 1
dave
  • 117
  • 2
  • 3
  • 13
  • 2
    Don't use `cin.fail()` and an `iValid` flag to test for the same state in your code. It falls under the adage "don't repeat yourself" in coding. Here, it's leading you to mismanage the state of your code because you are checking the two versions of the "same" state at different points in your code and you are getting confused. – Frank Bryce Oct 22 '15 at 15:25

3 Answers3

11

When cin fails, you need to clear the error flag. Otherwise subsequent input operations will be a non op.

To clear the error flags, you need to call cin.clear().

Your code would then become:

cin >> iUserSel;
while (iValid == 1)
{
    if (cin.fail())
    {
        cin.clear(); // clears error flags
        cin.ignore();
        cout << "Wrong! Enter a #!" << endl;
        cin >> iUserSel;
    }//closes if
    else
        iValid = 0;
}//closes while

I would also suggest you change

cin.ignore(); 

to

cin.ignore(numeric_limits<streamsize>::max(), '\n'); 

In case the user enters more than one letter.

Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
6

The problem you are having is that you don't clear the failbit from the stream. This is done with the clear function.


On a somewhat related note, you don't really need to use the fail function at all, instead rely of the fact that the input operator function returns the stream, and that streams can be used in boolean conditions, then you could do something like the following (untested) code:

while (!(std::cin >> iUserSel))
{
    // Clear errors (like the failbit flag)
    std::cin.clear();

    // Throw away the rest of the line
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    std::cout << "Wrong input, please enter a number: ";
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

Here's what I would recommend:

// Read the data and check whether read was successful.
// If read was successful, break out of the loop.
// Otherwise, enter the loop.
while ( !(cin >> iUserSel) )
{
   // If we have reached EOF, break of the loop or exit.
   if ( cin.eof() )
   {
      // exit(0); ????
      break;
   }

   // Clear the error state of the stream.
   cin.clear();

   // Ignore rest of the line.
   cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

   // Ask more fresh input.
   cout << "Wrong! Enter a #!" << endl;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270