Input and strings
Why std::getline skips input after std::cin
std::getline appears to skip a line when formatted input such as std::cin >> number leaves the newline in the stream. The next line read consumes that newline and returns an empty string. Read the pending line ending deliberately before asking for a whole line.
Understand the pending newline
Formatted extraction reads a value and stops when it reaches whitespace. For input containing 3, then Enter, the integer extraction consumes the digits and leaves the line break unread. std::getline reads characters through the next line break. If that delimiter is already the next character, the function consumes it and stores an empty line.
The stream is behaving consistently. The two input functions use different rules: operator >> skips leading whitespace and parses a value, while getline preserves spaces and reads to a delimiter. Mixing them requires you to decide whether the remainder of the current line matters.
Discard one line ending
When the program expects the next response on a new line, call ignore after successful formatted input. Use std::numeric_limits<std::streamsize>::max() with '\n' to discard characters through the end of the line. Include <limits>, which declares std::numeric_limits.
#include <iostream>
#include <string>
void printNote(int quantity, const std::string& note) {
std::cout << quantity << ": [" << note << "]\n";
}
int main() {
int quantity = 0;
std::string note;
if (!(std::cin >> quantity)) {
return 1;
}
std::getline(std::cin, note);
printNote(quantity, note);
return 0;
}
This program stores an empty note because the first line read consumes the pending newline. Its expected output is an empty bracket pair after the number. Add ignore before getline when the note belongs on the following line.
#include <iostream>
#include <limits>
#include <string>
void printNote(int quantity, const std::string& note) {
std::cout << quantity << ": [" << note << "]\n";
}
int main() {
int quantity = 0;
std::string note;
if (!(std::cin >> quantity)) {
return 1;
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (!std::getline(std::cin, note)) {
return 1;
}
printNote(quantity, note);
return 0;
}
Expected output:
2: [ fragile]
The exact spaces inside the brackets are part of the input line and remain present.
Choose between ignore and ws
std::ws consumes leading whitespace before the next extraction. A common pattern is std::getline(std::cin >> std::ws, line). This is concise when leading spaces are insignificant. It also removes intentional spaces at the start of the user's line, so it is unsuitable when those characters belong to the text.
ignore through newline preserves the next line exactly. Use it when the current formatted line is complete and the following full line is the next field. If the user typed extra text after the number on the same line, ignore discards that text too. Choose based on the input format rather than applying either call mechanically.
Recover after failed input
If extraction fails because the input is not a number, the stream enters a failed state. Further reads do not proceed until the state is cleared. Call std::cin.clear() to reset the state, then discard the invalid line with ignore before asking again. Clearing alone does not remove the bad characters, and ignoring alone does not reset the failure flag.
Check each read before using the corresponding value. If input ends, do not loop forever asking for another line. A loop should exit when extraction fails at end of file. For interactive retry logic, report what input format the program expects and discard the entire invalid line so the next attempt starts at a known boundary.
Do not call ignore before every getline. Consecutive line reads already consume their own delimiters. The discard step is needed at the transition from formatted extraction to line-oriented input, or after intentionally rejecting a line. Repeated unconditional ignores can throw away valid user text.
Keep input parsing predictable by choosing one format for each field. Use formatted extraction for tokens such as counts and menu choices. Use getline for text where spaces matter. When you switch from tokens to lines, put the transition logic next to the first line read and explain what it consumes. Future edits can then preserve that boundary when the input sequence changes.
Exercise
Read a count, then read that many complete lines. Print every line inside brackets and preserve any spaces in its text. Sample input:
2 red apple fragile
Expected output:
[red apple] [ fragile]
Hint 1: Read the count with >>, then discard the rest of its line. Hint 2: Call getline once for each remaining line.
Show one possible solution
#include <iostream>
#include <limits>
#include <string>
int main() {
int lineCount = 0;
if (!(std::cin >> lineCount) || lineCount < 0) {
return 1;
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
for (int index = 0; index < lineCount; ++index) {
std::string line;
if (!std::getline(std::cin, line)) {
return 1;
}
std::cout << '[' << line << "]\n";
}
return 0;
}
Related guides
- Validate input and recover failed streams
- Read sequences with std::vector
- Control input loops with C++ loops
Keep learning with CppPath
Continue with the Input & Output lesson. The full lesson includes a quiz and a checked coding challenge with a free account.