std::cin failure leading to looped if statement in while loop

258 Views Asked by At

So I figure I'll put this here since I had to traverse a lot of docs and forums to find the definitive answer. I was trying to get input from the user and check if the input was an integer using isdigit() in an if statement. If the if statement failed the program would output an error message. Although, when a nondigit character was entered the program would loop through the error message endlessly. Here's that code:

int guess = -1;
while (game.getCurQuestion() <= 4) {
    std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
    std::cin >> guess;
    if(isdigit(guess))
    {
        game.guess(guess);
    else
    {
        std::cout << "Error\n"; //this would be looped endlessly
    }
    
}
std::cout << "You got " << game.getCorrect() << " correct"  << std::endl;
return 0;

}

NOTE: Solved, only posted to include my solution. Feel free to correct if I stated anything incorrectly.

2

There are 2 best solutions below

1
CrypticEthos On

Problem: The program kept hold of the non-integer value stored in the cin buffer. This leads to the program never leaving the error message.

Solution:

  1. Use std::cin.fail() to check if the input matches the variable data type. I.E. int was the expected input but the user entered a char. In this case std::cin.fail() would be true.
  2. In the case of std::cin.fail(), use std::cin.clear() and std::cin.ignore(std::numeric_limits<int>::max(), 'n') std::cin.clear() will clear the error flag. The std::cin.ignore(std::numeric_limits<int>::max(), 'n') will ignore any other input that is not an integer and will skip to the new line. Effectively progressing the program.

The solution implemented in my code looks like this:

int guess = -1;
while (game.getCurQuestion() <= 4) {
    std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
    std::cin >> guess;
    if (std::cin.fail())
    {
        std::cout << "Please enter a valid number\n";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<int>::max(), '\n');
    }
    game.guess(guess);
}

Hope this helps and that it saves some people the tedious research because of never learning std::cin error handling! Note: I'm aware my implementation skips the current move, call it punishment ;)

3
asmmo On

The posted way will fail sometimes and will cast the doubles to integers if any doubles are input.

Use something like the following

int getIntInput() {
    try {
        std::string input;
        std::cout << "\nPlease Enter a valid Integer:\t";
        std::cin >> input;
        size_t takenChars;
        int num = std::stoi(input, &takenChars);
        if (takenChars == input.size()) return num;
    } catch (...) {}
    return getIntInput();
}