1

Possible Duplicate:
How to validate numeric input C++

How do you do the following:

while (iNumberOfPlayers <2 || iNumberOfPlayers >5)
{
    cout << "Enter number of players (1-4): ";
    cin >> iNumberOfPlayers;
    cin.clear();
    std::string s;
    cin >> s;
}

After looking at the loop I'm thrown in, it looks like cin isn't getting reset (if I put in x) cin reads X again as long as I'm in the while loop. Guessing this is a buffer issue, any way to clear it?

I then tried:

while (iNumberOfPlayers <2 || iNumberOfPlayers >5)
{
    cout << "Enter number of players (1-4): ";
    cin >> iNumberOfPlayers;
    cin.clear();
    cin.ignore();
}

which works except it reads everything 1 at a time. If I put in "xyz" then the loop goes through 3 times before it stops to ask again.

Community
  • 1
  • 1
Matt Westlake
  • 3,499
  • 7
  • 39
  • 80
  • 1
    you need to declare a, like `int a = 0;` – ThomasMcLeod Jul 14 '12 at 14:46
  • 2
    But if you declare `a` as an int, won't that make it very difficult for a to not be an int? – Simon Forsberg Jul 14 '12 at 14:47
  • @SimonAndréForsberg int a = 0; cin << a; if someone puts in something not an int (x for example) the whole program crashes. – Matt Westlake Jul 14 '12 at 14:49
  • Matt, your post title asks about testing whether a string can be tested to be an int, but your code has no strings in it. cin does not read things in as strings automatically. I just tested putting in bad data, and 'a' simply remains '0'. – Thomas Thorogood Jul 14 '12 at 14:53
  • @MattWestlake I suspected that. In which case @ThomasMcLeod's solution would crash your program... Then how have you declared `a`? That's a quite important thing to know. – Simon Forsberg Jul 14 '12 at 14:53
  • see also: http://stackoverflow.com/questions/2032719/c-cin-fail-question – Doug T. Jul 14 '12 at 14:55
  • 1
    @Matt: No, if the program crashed because someone put non-numeric data in, it is because your code didn't check whether the input failed. The *stream* will not *crash* when trying to parse invalid input. – Ben Voigt Jul 14 '12 at 14:58
  • @Matt: Looking at your edited question, you aren't using `cin.clear()` the way my answer shows. – Ben Voigt Jul 14 '12 at 15:01
  • called cin.clear(); and it just looped me still – Matt Westlake Jul 14 '12 at 15:03
  • @Matt: yeah, you're right that you also have to remove the trash from the buffer. Look at my answer again. – Ben Voigt Jul 14 '12 at 15:04
  • getting a "no operator >> matches these operands" error on the last cin >> s statement – Matt Westlake Jul 14 '12 at 15:07
  • @MattWestlake - you need to keep the `cin >> a` inside the condition of the loop, not within the body of the loop ideally. I've updated my example to show this. – Flexo Jul 14 '12 at 15:31

2 Answers2

7

If the input is not valid, the fail bit is set on the stream. The ! operator used on a stream reads the fail bit (You could also use (cin >> a).fail() or (cin >> a), cin.fail()).

Then you just have to clear the fail bit before trying again.

while (!(cin >> a)) {
    // if (cin.eof()) exit(EXIT_FAILURE);
    cin.clear();
    std::string dummy;
    cin >> dummy; // throw away garbage.
    cout << "entered value is not a number";
}

Please note that if you're reading from non-interactive input, this would become an infinite loop. So use some variation on the commented error-detection code.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • That doesn't work, if I enter "hello" then it keeps repeating "value is not a number" because `cin.clear()` leaves the string in the input. You need to consume the non-`int` input too before repeating. – Flexo Jul 14 '12 at 15:02
  • 1
    @Flexo: Your comment crossed my edit somewhere out in the internet. Should work now. – Ben Voigt Jul 14 '12 at 15:06
3

The tricky thing is that you need to consume any invalid input as failure to read doesn't consume the input. The simplest solution to this is to move the call to operator >> into the loop condition and then read up to the \n if it didn't mange to read an int:

#include <iostream>
#include <limits>

int main() {
  int a;
  while (!(std::cin >> a) || (a < 2 || a > 5)) {
    std::cout << "Not an int, or wrong size, try again" << std::endl;
    std::cin.clear(); // Reset error and retry
    // Eat leftovers:
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  }
}
Flexo
  • 87,323
  • 22
  • 191
  • 272