C++ fundamentals

How to validate user input in C++

Input validation checks whether data can be read and whether its value is allowed for the task. In C++, formatted extraction with std::cin >> value returns the stream, whose state tells you whether the operation succeeded. Check that state before using the variable. A failed read can leave the destination unchanged and put the stream into a failed state.

Check extraction before use

Use the extraction expression as a condition: if (std::cin >> count). C++ attempts to parse the next token as the type of count. If the token cannot be parsed as an integer, the condition is false. If the input ends before a token arrives, extraction also fails. Branch on failure instead of assuming a read worked.

Validation has two stages. First, check that extraction produced a value of the right type. Then check that the value fits the rules of your program. A successfully read integer can still be outside an allowed range. Keep these checks separate so the code distinguishes malformed text from a valid number that the task does not accept.

#include <iostream>

int main() {
    int seats = 0;
    if (!(std::cin >> seats)) {
        std::cout << "Enter a whole number\n";
        return 1;
    }
    if (seats < 1) {
        std::cout << "Seat count must be positive\n";
        return 1;
    }
    std::cout << "Seats: " << seats << '\n';
    return 0;
}

Expected output for input bad:

Enter a whole number

The program stops after invalid data, so it does not need to repair the stream. This is appropriate for a one-shot command. An interactive program that asks again needs to reset the stream before the next extraction.

Recover from invalid input

When formatted extraction fails on a bad token, the failure state prevents later reads. Call std::cin.clear() to reset the state flags. Then discard the invalid input with ignore(). The header <limits> provides std::numeric_limits<std::streamsize>::max(), a bound you can pass to ignore the rest of the current line.

Do not call clear() without removing or consuming the bad characters. The next extraction would encounter the same token and fail again. Also do not discard input before deciding what the interface promises. Ignoring to the newline is a useful policy when one response occupies one line; token-oriented programs may choose a different policy.

#include <iostream>
#include <limits>

int main() {
    int age = 0;
    while (!(std::cin >> age)) {
        if (std::cin.eof()) {
            return 1;
        }
        std::cout << "Try again\n";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    std::cout << age << '\n';
    return 0;
}

Expected output for input abc followed by 7:

Try again
7

The loop repeats only after it resets the failure and removes the rest of the bad line. The end-of-file check avoids asking forever when no more input can arrive. This example checks the type, not an application-specific age range; add a separate condition when the program needs one.

Handle end of input

End of file is a normal way for input to finish. A loop such as while (std::cin >> value) processes values until extraction fails. If the failure means end of input, stop cleanly. If it means malformed data, decide whether to reject the line, ask again, or stop with an error. The right response depends on whether the program is interactive or processing a file.

Mixing >> with std::getline needs care. Formatted extraction leaves the newline after the token in the stream. A following getline can read that leftover newline and return an empty string. Consume the remainder of the line when that matches the input format, or read complete lines and parse each line separately.

For line-based validation, use std::getline to retain spaces and then parse the resulting string with an input string stream. This lets the program reject extra characters on the same line. Choose that approach when a response must contain exactly one value rather than a sequence of whitespace-separated tokens.

Exercise

Read three nonnegative whole-number measurements. If a token is not an integer, discard the rest of that line and try again for the same measurement. Print the total after you collect three values. Sample input:

12
oops
8
5

Expected output:

25

Hint 1: Keep the accepted-value count separate from the input attempt. Hint 2: On failed extraction, check for end of input before clearing the stream.

Show one possible solution
#include <iostream>
#include <limits>

int main() {
    int accepted = 0;
    long long total = 0;
    while (accepted < 3) {
        int measurement = 0;
        if (!(std::cin >> measurement)) {
            if (std::cin.eof()) {
                return 1;
            }
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            continue;
        }
        if (measurement < 0) {
            continue;
        }
        total += measurement;
        ++accepted;
    }
    std::cout << total << '\n';
    return 0;
}

Read the loop guide and the integer overflow guide next.

Keep learning with CppPath

Continue with the Validating Input with while lesson. The full lesson includes a quiz and a checked coding challenge with a free account.