How to make cin take only numbers

Here is the code

double enter_number()
{
  double number;
  while(1)
  {

        cin>>number;
        if(cin.fail())
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cout << "Invalid input " << endl;
        }
        else
        break;
        cout<<"Try again"<<endl;
  }
  return number;
}

My problem is that when I enter something like 1x, then 1 is taken as input without noticing the character that is left out for another run. Is there any way how to make it work with any real number e.g. 1.8?


Solution 1:

When cin encounters an input it can't properly read in to the variable specified (such as inputing a character into an integer variable), it goes into an error state and leaves the input in it's buffer.

You have to do several things to properly handle this scenario.

  1. You have to test for this error state.
  2. You have to clear the error state.
  3. You have to either alternatively handle the input data that generated the error state, or flush it out and reprompt the user.

The following code provides one of numerous methods of doing these three things.

#include<iostream>
#include<limits>
using namespace std;
int main()
{

    cout << "Enter an int: ";
    int x = 0;
    while(!(cin >> x)){
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cout << "Invalid input.  Try again: ";
    }
    cout << "You enterd: " << x << endl;        
}

You could just pass in some large value to cin.ignore like 1000 and it's likely to behave exactly the same for all practical purposes.

You can also test cin after the input attempt and handle it that way, something like if(!cin){//clean up the error} .

Check out the istream reference for other member functions to handle stream state: http://cplusplus.com/reference/iostream/istream/

Solution 2:

I would use std::getline and std::string to read the whole line and then only break out of the loop when you can convert the entire line to a double.

#include <string>
#include <sstream>

int main()
{
    std::string line;
    double d;
    while (std::getline(std::cin, line))
    {
        std::stringstream ss(line);
        if (ss >> d)
        {
            if (ss.eof())
            {   // Success
                break;
            }
        }
        std::cout << "Error!" << std::endl;
    }
    std::cout << "Finally: " << d << std::endl;
}