Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I tried to prompt user for input and do the validation. For example, my program must take in 3 user inputs. Once it hits non-integer, it will print error message and prompt for input again. Here is how my program going to be look like when running :

Enter number: a

Wrong input

Enter number: 1

Enter number: b

Wrong input

Enter number: 2

Enter number: 3

Numbers entered are 1,2,3

And here is my code:

double read_input()
{
    double input;
    bool valid = true;
    cout << "Enter number: " ;
    while(valid){
        cin >> input;
        if(cin.fail())
        {
            valid = false;
        }
    }
    return input;
}

My main method:

int main()
{
double x = read_input();
double y = read_input();
double z = read_input();
}

When my first input is non-integer, the program just exits by itself. It does not ask for prompting again. How could I fixed it? Or am I supposed to use a do while loop since I asking for user input.

Thanks in advance.

share|improve this question
we have to see more code.. have you checked it with a debugger? could be a crash... – Karoly Horvath Jun 5 at 7:52
inside the main method I just write double x = read_input(); double y = read_input(); double z = read_input(); Am I doing the wrong way? – Carol Jun 5 at 7:53

4 Answers

up vote 3 down vote accepted

When the reading fails, you set valid to false, so the condition in the while loop is false and the program returns input (which is not initialized, by the way).

You also have to empty the buffer before using it again, something like:

#include <iostream>
#include <limits>

using namespace std;

double read_input()
{
    double input = -1;
    bool valid= false;
    do
    {
        cout << "Enter a number: " << flush;
        cin >> input;
        if (cin.good())
        {
            //everything went well, we'll get out of the loop and return the value
            valid = true;
        }
        else
        {
            //something went wrong, we reset the buffer's state to good
            cin.clear();
            //and empty it
            cin.ignore(numeric_limits<streamsize>::max(),'\n');
            cout << "Invalid input; please re-enter." << endl;
        }
    } while (!valid);

    return (input);
}
share|improve this answer
When I put a cout in else statement and I typed in non-integer, the error message itself just keep looping. – Carol Jun 5 at 7:58
I cannot test the code, but Ideone has the same output, let me check why. – Djon Jun 5 at 8:14
@Carol It works now, I guess it was the order between clear and ignore: ideone.com/fl4IMK – Djon Jun 5 at 8:29
Okay thanks a lot. But why you initialize the input as -1 and what's the use of flush? – Carol Jun 5 at 8:35
@Carol In C and C++ I always initialize my values (Java complains about it, so I always do it now), you cannot exit the function without reading a correct value so it is not necessary. Flush is to make sure that the standard input buffer is correctly displayed, I was thought that way, you can remove it if you want. (endl is '\n' + flush I think). – Djon Jun 5 at 8:38
show 1 more comment

Your question did get myself into other issues like clearing the cin on fail() --

double read_input()
{
double input;
int count = 0; 
bool valid = true;
while(count != 3) {
    cout << "Enter number: " ;
    //cin.ignore(); 
    cin >> input; 
    if(cin.fail())
    {
        cout << "Wrong Input" <<endl;
        cin.clear(); 
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
    }
    else 
            count++;
}
return input;
}
share|improve this answer

The problem is in the while condition

bool valid = true;
while(valid){

You loop until you get a non valid input, this absolutly not what you want! loop condition should be like this

bool valid = false;
while(! valid){ // repeat as long as the input is not valid

Here is a modified version of your read_double

double read_input()
{
    double input;
    bool valid = false;
    while(! valid){ // repeat as long as the input is not valid
        cout << "Enter number: " ;
        cin >> input;
        if(cin.fail())
        {
            cout << "Wrong input" << endl;

            // clear error flags
            cin.clear(); 
            // Wrong input remains on the stream, so you need to get rid of it
            cin.ignore(INT_MAX, '\n');
        }
        else 
        {
            valid = true;
        }
    }
    return input;
}

And in your main you need to ask for as may doubles as you want, for example

int main()
{
    double d1 = read_input();
    double d2 = read_input();
    double d3 = read_input();

    cout << "Numbers entered are: " << d1 << ", " << d2 << ", " << d3 << endl;

    return 0;
}

You may also want to have a loop where you call read_double() and save the returned values in an array.

share|improve this answer
Okay thanks alot. I used cin.clear() and getline in else statement and it works now – Carol Jun 5 at 8:44
  1. Read in a way that won't mess up your ability to read from std::cin just because they didn't enter a valid integer. It's not trivial to carry on reading after this. I recommend using std::getline to read a line of text at a time, then process it in any way you like inside your program.
  2. Read and check the stream state as part of the loop condition. Then check it was a valid integer and decide what to do based on that. This is where the formatted input (>>) is useful.

Here's a less than perfect example I just put together:

#include <iostream>
#include <string>
#include <sstream>

bool promptAndRead (std::string& line)
{
    std::cout << "Please enter an integer: ";
    // This does the read, then implicitly converts the stream
    // to true or false based on whether it is in a sensible state.
    return std::getline(std::cin, line);
}

int main()
{
    std::string line;
    int validIntsRead = 0;

    // Read. If this stops (before 3 valid ints are read) then the user
    // has hit ctrl-D, and you can't carry on reading anyway.
    while ( validIntsRead < 3 && promptAndRead(line) )
    {
        // Check it was a valid int.
        std::istringstream iss {line};
        int tempInt;
        if ( iss >> tempInt )
        {
            std::cout << "Valid integer.\n";
            ++validIntsRead;
        }
        else
        {
            std::cout << "Not a valid integer. Please try again.\n";
        }
    }

    return 0;
}

Since I see a lot of beginner questions on reading input from a stream, I put together a little tutorial. Hasn't been around long enough yet to know if people are finding it useful though.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.