1
    int x; // intitialize x but don't immediately prompt for input. This makes the program more user friendly

    cout << "Enter a year to check if it's a leap year: " << endl;
    cin >> x;

    while (cin.fail()) // check for input error

    {
    cin.clear();
    cin.ignore();
    cout << "You entered an incorrect value. Try again" << endl;
    cin >> x;
    }

I'm having trouble understanding how fail states work in c++. What I want to happen is if the user inputs anything that contains something besides a number, It will clear the buffer and prompt for another input. My code doesn't seem the to do that. If I enter a something like say, r4, then the rest of my code (which works just fine so I didn't show it below) will run with the four. It seems like the loop is activated at some point. The cout string is still printed. It's just that It doesn't give me to opportunity to re-input and continue checking.

trashpanda
  • 93
  • 1
  • 13
  • I hope you know what [`cin.ignore();`](http://en.cppreference.com/w/cpp/io/basic_istream/ignore) does. – chris Feb 20 '15 at 17:48
  • 1
    See: http://stackoverflow.com/questions/10828937/how-to-make-cin-to-take-only-numbers – hlscalon Feb 20 '15 at 17:56

3 Answers3

3

The following table, obtained from http://en.cppreference.com/w/cpp/io/basic_ios/fail, shows the various states that affect the return value of istream::fail()

enter image description here

Given that, you should use:

while (cin.fail()) // check for input error
{
   if ( cin.eof() )
   {
      // Once EOF file has been reached with cin,
      // you can't do much. Figure out a way to bail
      // from the loop.
   }

   cin.clear();

   // Also, ignore not just one character but till the end of the line.
   // cin.ignore();
   cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

   cout << "You entered an incorrect value. Try again" << endl;
   cin >> x;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0
cin >> x;

cin checks if there's anything in it's buffer. The buffer is empty, so it waits until the user presses return, and then it copies everything into it's buffer (r4). Then it tries to load from the buffer into an int. The first byte is an r, so it sets the stream's failstate and aborts. r4 remains in the buffer.

cin.clear();

This clears the failstate, r4 remains in the buffer.

cin.ignore();

This ignores the first character in the buffer. 4 remains in the buffer.

cout << "You entered an incorrect value. Try again" << endl;
cin >> x;

cin checks if there's anything in the buffer, and there is (4), so it tries to load from the buffer into an int, which succeeds and continues as you see.

The usual solution is to use cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'), which ignores the rest of the line.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • But, like I said, it is looking for valid input, if someone sends an non-int, there will be problems (you know this...) Checking `cin.good` or `cin.clear()` will tell you (you know this...) – Evan Carslake Feb 20 '15 at 18:08
  • 1
    @EvanCarslake: `cin.clear()` tells you nothing, and the OP is already checking `cin.fail()`, so that advice is not helpful. – Mooing Duck Feb 20 '15 at 18:54
  • I think I understand the problem now. Thanks. For some reason this website doesn't allow to upvote the answer that I found most helpful for my question until I get more RP. Seems silly, but oh well. I have another total n00b question: For some reason when I put the correct use of cin.ignore (the way you did it) into my code and compile it I get a compilation error. Is there another module I need to include? I'm using codeblocks (not sure if that helps) and I only included iostream and strings. – trashpanda Feb 20 '15 at 20:26
  • @MadisonC.Brewer: [This site](http://en.cppreference.com/w/cpp/types/numeric_limits) says `numeric_limits` is "Defined in header ``" – Mooing Duck Feb 20 '15 at 20:57
-1

cin.good() or cin.fail() will let you know if it can deal with the input (valid.) cin.clear() clears the error state if needed.

Evan Carslake
  • 2,267
  • 15
  • 38
  • 56