Nyck
Nyck

Reputation: 183

Avoid bad user input (string when what's asked is an integer)

I have an infinite while loop, where the user is asked for a number.

My problem is very simple: If the input is a string, I want to re-ask user for input, outputting the message "Enter a valid choice: ".

I searched, and looks like I should check for cin.fail(), then call cin.clear() and cin.ignore().

Here's my code:

int main() {
    int choice;
    bool failed = false;
    while (true) {
        if (failed) cout << "Enter a valid choice: ";
        else cout << "Enter a number: ";
        cin >> choice;

        if (cin.fail()) {
            cin.clear();
            cin.ignore();
            failed = true;
        }
    }

    return 0;
}

However, this doesn't really fix my problem. Of course, it isn't printing infinitely, but for each letter extra letter , it prints another "Enter a valid choice:"

Seems like I need to call cin.ignore() for each extra letter.

Any other way of doing this?

Upvotes: 1

Views: 316

Answers (2)

Captain Claw
Captain Claw

Reputation: 31

The reason it is printing so many times is because you are only clearing the state of cin, but aren't clearing the input buffer. You can do so in multiple ways:-

  1. Use fflush(stdin) to clear the input buffer.This is the C method and can be done by including cstdio header.

  2. Use the cin.ignore to ignore all characters in the current input stream. You can do this by replacing the line cin.ignore() which ignores a single character by this code cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') which ignores the entire line. For this you need the limits header.

  3. Finally you can do the same with a simple loop like while (cin.get() != '\n'){continue;} which ignores all characters till new line.

Also another approach to the same problem is to take the input in form of a string and use the strtol() or the isdigit() functions to check if the input is valid.

By the way the infinite loop is because you have not used the break statement to terminate the loop. So you can avoid this by adding

if(!failed)
   break;

Also you need to change the state of Failed at the entry of each loop by adding

failed=false;

at the start of the loop body.

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 596352

You have an infinite loop because you are not breaking the loop even when valid input is enter. Is that what you really want? If so, at the least, you are not resetting the failed flag in valid input.

More importantly, when invalid input is entered, you are not ignoring everything that was enteted, you are only ignoring 1 char at a time. That is why you see extra prompts.

Try this instead :

int main() {
    int choice;
    while (true) {
        cout << "Enter a number: ";
        while (!(cin >> choice)) {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cout << "Enter a valid choice: ";
        }
    }
    return 0;
}

Upvotes: 1

Related Questions