8
votes

I found this link at http://www.parashift.com/c++-faq-lite/istream-and-ignore.html

which shows "How can I get std::cin to skip invalid input characters?"

Use std::cin.clear() and std::cin.ignore().

#include <iostream>
#include <limits>

int main()
{
  int age = 0;

  while ((std::cout << "How old are you? ")
         && !(std::cin >> age)) {
    std::cout << "That's not a number; ";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  }

  std::cout << "You are " << age << " years old\n";
  ...
}
Of course you can also print the error message when the input is out of range. For example, if you wanted the age to be between 1 and 200, you could change the while loop to:
  ...
  while ((std::cout << "How old are you? ")
         && (!(std::cin >> age) || age < 1 || age > 200)) {
    std::cout << "That's not a number between 1 and 200; ";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  }
  ...
Here's a sample run:
How old are you? foo
That's not a number between 1 and 200; How old are you? bar
That's not a number between 1 and 200; How old are you? -3
That's not a number between 1 and 200; How old are you? 0
That's not a number between 1 and 200; How old are you? 201
That's not a number between 1 and 200; How old are you? 2
You are 2 years old

I am not able to get how it is doing it > Can any one explain please?

I have doubts with :

while ((std::cout << "How old are you? ")
             && !(std::cin >> age)) 

How is it checking the valid entry? I mean to ask do expressions "std::cout << "How old are you?" and "!(std::cin >> age)" , return true or false which are being ANDed ?

another thing which is confusing is the usage,

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

What are there purpose ? Searched on google about these functions but still I am not clear. Particularly, std::numeric_limits<std::streamsize>::max()

Can any one help? Thanks

3
cin.clear() and cin.ignore() is for preventing cin for being skipped, (if doesn't wrong). For the first while, I guess it is the wrong one being asked.oentoro

3 Answers

10
votes

The insertion and extraction operators << and >> on streams will return a reference to the stream itself. That's why you can string together insertions like so:

std::cout << "Hello, " << "World!";

First std::cout << "Hello, " returns a reference to std::cout and then you have the equivalent of std::cout << "World!".

The streams can also be converted to bool. This basically checks that the state of the stream is still okay. Nothing has failed. For example, you could do this:

if (std::cin) // ...

This would check if the std::cin stream is still in a good state.

Now let's look at the code you asked about:

while ((std::cout << "How old are you? ")
         && !(std::cin >> age))

The insertion into std::cout won't cause a failure. The only reason it's included here is so that it occurs every time before the input to age. The alternative would be to place it once before the while and once at the end of the while body.

After the insertion to std::cout is done, !(std::cin >> age) will be evaluated. This will first get the user to provide an age. Then two things can happen:

  1. If this fails in some way (perhaps the user enters characters rather than an integer), then the fail bit will be set. This means that the result of std::cin >> age will be converted to a bool which will be false. The ! will invert it to true. So because both the first and second condition were true, the body of the while loop will execute, telling the user that they entered an invalid value and the loop will iterate round again.

  2. if the input succeeds, the result of std::cin >> age will be true and ! will turn it to false. This means the body of the while loop will not execute and will not tell the user that they entered the incorrect value.

Now let's look at:

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

This only happens in case 1 above, when the input failed. If a stream goes into a failure state, it will not accept any more insertions or extractions until the state has been cleared. that's what clear() does. Then the call to ignore says to extract all characters up to and including the next \n in the stream and discard them. This gets rid of the invalid input from the stream.

1
votes
while ((std::cout << "How old are you? ")        && !(std::cin >> age)) 

cout is a global object of class ostream and cin is a global object of class istream

These objects are used along the overloaded operators << (defined in ostream)and >> (defined in istream) to take input (by calling the functions defined for these operators)

The return type of operator<< is of type ostream& and that of operator>> is istream&. These are then converted to boolean values. See this.

Check this too for cin.ignore() and cin.clear()

0
votes

std::numeric_limits allows you to obtain maximum number that can fit in a given type.

In your example, it's passed to ignore() function, which basically means ignoring every newline character upfront.