cin input (input is an int) when I input a letter, instead of printing back incorrect once, it prints correct once then inc for the rest of the loop

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.

Leave a Comment