cin input (input is an int) when I input a letter,

2019-03-06 14:16发布

问题:

I'm making a multiplication practice program. As my title says, if I enter a letter into the console instead of a number, it will run off saying correct on the first one, but incorrect on the rest. Even if you're not touching the keyboard, it'll still spit out incorrect.

ans = table * i;
                    std::cout << table << " * " << i << " =" << std::endl;
                    std::cin >> input;
                    if(input == ans)
                    {
                            std::cout << "Correct! " << ans << std::endl;
                    }
                    else
                    {
                            std::cout << "Incorrect, the answer was " << ans << std::endl;
                            input = 0;
                            ans = 0;
                    }
            }

Hopefully that gives you a view of what's happening in the code. Here's the output.

Enter the table you'd like to learn.
5
Enter the amount of multiples
3
5 * 0 =
s
Correct! 0
5 * 1 =
Incorrect, the answer was 5
5 * 2 =
Incorrect, the answer was 10
5 * 3 =
Incorrect, the answer was 15

What could I do to fix this problem? Thanks for your input.

回答1:

There are a number of ways to structure the various test, but when taking input with cin (or generally with any input function), you must account for any characters in the input buffer that remain unread. With cin, you have three conditions you must validate:

  1. .eof() (eofbit) is set. Either the end of input was reached, or the user manually generated an EOF by pressing Ctrl+d (or Ctrl+z on windoze, but see: CTRL+Z does not generate EOF in Windows 10);

  2. .bad() (badbit) is set. An unrecoverable stream error occurred; and

  3. .fail() (failbit) is set. A matching, or other recoverable, failure occurred. When the failure occurs input stops and no further characters are extracted from the input buffer.

(you can combine 1 & 2 into a single test as input is over at that point)

With failbit, you must do two things. (1) you must clear the stream error state by calling cin.clear(), and (2) you must handle any characters that remain unread in the input buffer. Generally this is handled by including <limits> and calling:

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

(which will clear up to INT_MAX characters from the input buffer, stopping when the delimiter ('\n' here) is encountered)

A short example that loops until a valid integer is input by the user could be:

#include <iostream>
#include <limits>

using namespace std;

int main (void) {

    int x = 0;

    while (1)       /* loop continually until valid input received */
    {
        cout << "\nenter an integer: ";
        if (! (cin >> x) ) {            /* check stream state */
            /* if eof() or bad() break read loop */
            if (cin.eof() || cin.bad()) {
                cerr << "(user canceled or unreconverable error)\n";
                return 1;
            }
            else if (cin.fail()) {      /* if failbit */
                cerr << "error: invalid input.\n";
                cin.clear();            /* clear failbit */
                /* extract any characters that remain unread */
                cin.ignore(numeric_limits<streamsize>::max(), '\n');
            }
        }
        else {  /* on succesful read of int */
                /* extract any characters that remain unread */
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            break;  /* then break read loop */
        }
    }

    cout << "integer: " << x << '\n';
}

(as mentioned at the beginning, you can structure the tests many different ways, as long as you cover all three conditions.)

Additionally, you can check the stream bit explicitly by calling rdstate() instead of testing with .fail(), etc..., e.g.

if (std::cin.rdstate() == std::ios_base::failbit)

Example Use/Output

$ ./bin/cin_validate_int

enter an integer: no
error: invalid input.

enter an integer: "an integer"
error: invalid input.

enter an integer: abc 123
error: invalid input.

enter an integer: 123
integer: 123

Look things over and let me know if you have further questions.



回答2:

When you do cin >> input and it can't parse the input as a number, it sets cin's failbit, and when failbit is set it doesn't actually read any more data until you clear it.

You should check for errors by calling cin.good(), and try to clear them with cin.clear(), but you shouldn't try to clear some errors (like EOF) and instead should quit on them.