Skip to content
C++ Better Explained
Go back
C++ Input Validation: Handling Bad cin Input Without Crashing

C++ Input Validation: Handling Bad cin Input

Short answer: test the read with if (std::cin >> value). If it fails, call std::cin.clear() then std::cin.ignore(...) before asking again — otherwise your program spins in an infinite loop.


The Bug Everyone Hits First

#include <iostream>

int main() {
    int age;
    while (true) {
        std::cout << "Enter your age: ";
        std::cin >> age;
        if (age > 0) break;
        std::cout << "Invalid, try again\n";
    }
}

Type abc and this prints “Enter your age: Invalid, try again” thousands of times per second, forever.

Here is why. When cin >> age meets characters that are not a number:

  1. The extraction fails and age is left unset (C++11 and later set it to 0).
  2. The offending characters stay in the buffer — they are not consumed.
  3. The stream enters a fail state, and every future read returns immediately without waiting for input.

So the loop keeps re-reading the same bad characters and never pauses for the user again.

The Fix: clear() and ignore()

#include <iostream>
#include <limits>

int main() {
    int age;
    while (true) {
        std::cout << "Enter your age: ";

        if (std::cin >> age) {
            if (age > 0) break;
            std::cout << "Age must be positive.\n";
        } else {
            std::cin.clear();   // reset the fail state
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            std::cout << "That is not a number.\n";
        }
    }

    std::cout << "You are " << age << '\n';
}

The two recovery calls do different jobs, and you need both:

Miss clear() and reads keep failing. Miss ignore() and you re-read the same garbage. That interaction is covered in more depth in cin.ignore and clearing the input buffer.

Learning C++ properly? The C++ Better Explained Ebook explains input, strings and the STL in plain English — 87 pages, just $19.

A Reusable Input Function

Write it once and stop repeating yourself:

#include <iostream>
#include <limits>
#include <string>

int readInt(const std::string& prompt) {
    int value;
    while (true) {
        std::cout << prompt;
        if (std::cin >> value) {
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            return value;
        }
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "Please enter a whole number.\n";
    }
}

int main() {
    int age = readInt("Enter your age: ");
    std::cout << "You are " << age << '\n';
}

Note the ignore on the success path too. That discards anything left on the line — so 42abc gives you 42 and cleanly drops the rest, and a following getline is not derailed by the leftover newline.

Validating a Range

int readIntInRange(const std::string& prompt, int lo, int hi) {
    while (true) {
        int v = readInt(prompt);
        if (v >= lo && v <= hi) return v;
        std::cout << "Enter a number between " << lo << " and " << hi << ".\n";
    }
}

int choice = readIntInRange("Choose 1-5: ", 1, 5);

This is the backbone of any menu-driven program.

Strict Validation: Rejecting “12abc”

cin >> n on 12abc succeeds and gives you 12, leaving abc behind. If you want the whole input to be a valid number, read the line and parse it:

#include <sstream>

bool parseInt(const std::string& text, int& out) {
    std::istringstream ss(text);
    char leftover;
    return (ss >> out) && !(ss >> leftover);   // nothing may remain
}

int main() {
    std::string line;
    int n;
    while (true) {
        std::cout << "Enter a number: ";
        std::getline(std::cin, line);
        if (parseInt(line, n)) break;
        std::cout << "Whole numbers only.\n";
    }
    std::cout << n << '\n';
}

Reading with getline throughout also sidesteps the mixing problem entirely — you never have a stray newline sitting in the buffer.

Checking the Stream State

CallTrue when
cin.good()Everything is fine
cin.fail()The last read failed (wrong type, or formatting)
cin.eof()End of input was reached (Ctrl+D / Ctrl+Z)
cin.bad()Unrecoverable stream corruption

Watch out for end of input: if the user presses Ctrl+D, cin hits EOF and clear() + retry loops forever again. A robust loop checks for it:

if (std::cin.eof()) {
    std::cout << "\nInput closed.\n";
    return 1;
}

Quick Reference

ProblemFix
Infinite loop on bad inputcin.clear(); cin.ignore(max, '\n');
getline skipped after cin >>cin.ignore(max, '\n'); before the getline
12abc accepted as 12Read with getline + parse with stringstream
Need a valid rangeLoop until v >= lo && v <= hi
Ctrl+D causes a spinCheck cin.eof() and exit

Take Your C++ Further

If you want input handling and the rest of the fundamentals explained properly rather than patched together, the C++ Better Explained Ebook covers it in plain English. Just $19.

👉 Get the C++ Better Explained Ebook — $19


📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Previous Post
How to Append to a File in C++ (std::ios::app)
Next Post
How to Insert Into a Vector in C++ (insert, emplace, push_back)

Keep Learning