AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

18 Streams and files / Lesson 2 of 5

Reading structured input — the pattern catalogue

15 min · +10 XP · 2 exercises · 6 questions

Read the text15 min
Exercises0/2
Quiz6 q

Quick answer

Why does getline skip input after cin in C++?

std::getline seems to skip a line after std::cin >> n because >> stops at the newline that ends the number and leaves it in the buffer; the next getline reads up to that newline and returns an empty string. Discard the rest of the count's line with std::cin.ignore, using the maximum count and the newline as delimiter, or read the line with std::getline(std::cin >> std::ws, line).

Every judged program, log parser and configuration reader starts with the same question: what shape is the input, and which read matches that shape? Most wrong answers on this platform are reading bugs, not logic bugs — a count read with >> followed by a getline that returns an empty line, a matrix read token by token that never notices a short row, a loop on eof() that runs once too often. This lesson is a catalogue. For each shape there is a template you can paste, the state check that makes it robust, and the validation that turns "it crashed somewhere" into "line 7: expected 3 values, got 2".

Choosing the read

Two reads, one rule. >> when whitespace is only a separator and the line layout carries no meaning; std::getline when spaces are data (a name, a sentence) or when which line something is on matters. When a line has internal structure, do both: getline the line, then parse it with a std::istringstream (lesson 4), so a malformed line can only break its own parse and never the state of std::cin. Never mix >> and getline on the same stream without dealing with the newline >> leaves behind.

Shape 1: a count, then N tokens

int n;
if (!(std::cin >> n) || n < 0) { std::cout << "bad count\n"; return 0; }
std::vector<long long> a(n);
for (auto& x : a) std::cin >> x;

Layout-agnostic: 3 10 20 30 and 3 on its own line followed by three lines read identically. The count is validated before it sizes anything — a negative or missing n would otherwise be a huge allocation or an uninitialised loop bound. long long unless the prompt bounds the values.

Shape 2: a count, then N lines

int n;
std::cin >> n;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');   // finish the count's line
for (int i = 0; i < n; ++i) {
    std::string line;
    std::getline(std::cin, line);
    if (!line.empty() && line.back() == '\r') line.pop_back();       // a Windows-edited file
    // use line
}

The ignore is the whole difference between this and a bug: without it the first getline returns the empty remainder of the count's line. The \r check costs nothing and is the difference between a parser that works on files from every editor and one that mysteriously fails on the last field of every line.

Shape 3: tokens until the input ends

long long x;
while (std::cin >> x) { /* every token */ }

The loop ends on the first failed read — the end of the input, or a bad token; lesson 1's recovery loop tells the two apart when it matters.

Shape 4: lines until the input ends, each with structure

std::string line;
int lineNo = 0;
while (std::getline(std::cin, line)) {
    ++lineNo;
    if (line.empty()) continue;                 // blank lines are not records
    std::istringstream fields(line);
    std::string name;
    int qty;
    double price;
    if (!(fields >> name >> qty >> price)) {
        std::cout << "line " << lineNo << ": malformed\n";
        continue;
    }
    // use the record
}

This is the workhorse for records. Each line gets a fresh istringstream, so a failure is local: the outer getline loop is untouched and simply moves to the next line. The line number is counted here, at the only place that sees every line, and it is what a useful error message names.

Shape 5: a header, then records

A first line that describes the rest — 3 items, width=80, a column list — is Shape 2's count with extra fields, read with >> into as many variables as it has, followed by an ignore to the end of that line before the records begin. When a record's last field can contain spaces (42 3.5 Ada Lovelace), read the fixed fields with >> and the rest of the line with std::getline(fields >> std::ws, name) — the std::ws swallows the separator that >> stopped on.

Shape 6: a matrix

int rows, cols;
std::cin >> rows >> cols;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::vector<std::vector<long long>> m;
for (int r = 0; r < rows; ++r) {
    std::string line;
    if (!std::getline(std::cin, line)) { std::cout << "expected " << rows << " rows, got " << r << '\n'; return 0; }
    std::istringstream in(line);
    std::vector<long long> row;
    long long v;
    while (in >> v) row.push_back(v);
    if (static_cast<int>(row.size()) != cols) { std::cout << "row " << r + 1 << ": expected " << cols << " values, got " << row.size() << '\n'; return 0; }
    m.push_back(std::move(row));
}

Two templates exist and they differ in what they can check. The token-wise version (for r, for c: std::cin >> m[r][c]) is shorter and accepts any layout, which also means it cannot notice that row 2 had four numbers and row 3 had two — it just reads twelve tokens. The line-wise version above validates every row against cols and reports the first violation with its row number. Use the token version when the prompt guarantees the shape; use the line version when it is the program's job to check it. A row with a non-number stops the inner while early, so it reports as too few values, which is the right message.

Shape 7: records with a variable number of fields

std::string name;
int k;
while (std::cin >> name >> k) {
    std::vector<int> values(k);
    for (auto& v : values) std::cin >> v;
    // use name, values
}

When each record announces its own length, the count leads and the loop follows — the same as Shape 1, repeated. When the length is not announced (ada 3 5 9 / bob 7), the line is the record: Shape 4's getline plus an istringstream that reads tokens until the line runs out, and values.size() is the count. The second form is the one that can validate ("at least one value expected") and the one that survives a missing field without swallowing the next record's name as a number.

Validating and reporting

Three rules make an error message worth reading. Name the position — the line number or record index the program counted. Say what was expected and what was found, with the values. And decide the policy once: stop at the first error (return after printing it) or skip and continue (print, continue, and keep a count of bad lines for a summary). A judged program prints its report to std::cout because that is what is compared; a real tool sends diagnostics to std::cerr so the data output stays clean for the next program in the pipeline. Never trust the count over the data: after a "count then N lines" read, a getline that fails before N lines arrived is an error to report, not a silent zero. And check the whole line was consumed when the format is strict — after reading the expected fields, if (fields >> extra) succeeding means there was trailing junk.

Pitfalls

MistakeWhat happens
std::getline right after std::cin >> nThe first "line" is empty. ignore the rest of the count's line.
A matrix read token-wiseA short or long row is never noticed; the numbers shift into the wrong cells.
Parsing fields straight from std::cinOne bad field sticks the stream; every later record is lost. Parse a line copy.
Ignoring \rThe last field of each line carries a stray carriage return and compares unequal.
Trusting n over the dataA short input reads garbage into the missing rows; report the shortfall instead.

Key takeaways

  • >> for tokens when layout is irrelevant; std::getline when spaces are data or the line matters; both when a line has structure.
  • After a count read with >>, ignore(max, '\n') before the first getline; strip a trailing \r.
  • Parse each line in its own std::istringstream so a malformed line cannot stick std::cin.
  • A line-wise matrix reader can validate row lengths; a token-wise one cannot.
  • Error messages name the line, the expectation and the value; decide stop-or-skip once.

Common questions

How do I read input until EOF in C++?

Loop on the read itself: while (std::cin >> x) for whitespace-separated tokens or while (std::getline(std::cin, line)) for lines. Each loop stops at the first failed read — the end of the input, or a token that is not the expected type.

When should I use getline instead of cin >>?

Use >> when whitespace is only a separator and the line layout does not matter. Use std::getline when spaces are part of the data, such as a full name, or when which line a value is on matters. When a line has internal structure, getline it and parse the copy with a std::istringstream.

How do I split a line into fields in C++?

Read the line with std::getline, wrap it in a std::istringstream, and extract the fields with >>; if (!(fields >> name >> qty >> price)) reports a malformed line. A fresh stream per line keeps a bad field from putting std::cin into a failed state and losing every later record.

How do I read a matrix from input in C++?

Read the row and column counts, then either read rows * cols tokens with >> when the shape is guaranteed, or read each row with getline and parse it with an istringstream when the program must check it. Only the line-wise version can detect a short or long row and report its row number.

Why does the last field of each line fail to match?

The input was probably saved with Windows line endings, so every line read by getline ends in a stray carriage-return character that makes its last field compare unequal. Check whether line.back() is a carriage return and pop_back() it before parsing.

Mark as readSign in to keep your place.

C++ Input Parsing: getline After cin and Reading Until EOF

Why getline returns an empty line after cin, how to read until end of input, parse lines with a stringstream, read a matrix and report bad lines in C++.

  • Course: C++ study plan
  • Module: Streams and files
  • Kind: Lesson
  • Reading time: 15 min
  • Runtime: Clang 18 · C++20

Why does getline skip input after cin in C++?

std::getline seems to skip a line after std::cin >> n because >> stops at the newline that ends the number and leaves it in the buffer; the next getline reads up to that newline and returns an empty string. Discard the rest of the count's line with std::cin.ignore, using the maximum count and the newline as delimiter, or read the line with std::getline(std::cin >> std::ws, line).

Lesson

Every judged program, log parser and configuration reader starts with the same question: what shape is the input, and which read matches that shape? Most wrong answers on this platform are reading bugs, not logic bugs — a count read with >> followed by a getline that returns an empty line, a matrix read token by token that never notices a short row, a loop on eof() that runs once too often. This lesson is a catalogue. For each shape there is a template you can paste, the state check that makes it robust, and the validation that turns "it crashed somewhere" into "line 7: expected 3 values, got 2".

Choosing the read

Two reads, one rule. >> when whitespace is only a separator and the line layout carries no meaning; std::getline when spaces are data (a name, a sentence) or when which line something is on matters. When a line has internal structure, do both: getline the line, then parse it with a std::istringstream (lesson 4), so a malformed line can only break its own parse and never the state of std::cin. Never mix >> and getline on the same stream without dealing with the newline >> leaves behind.

Shape 1: a count, then N tokens

int n;
if (!(std::cin >> n) || n < 0) { std::cout << "bad count\n"; return 0; }
std::vector<long long> a(n);
for (auto& x : a) std::cin >> x;

Layout-agnostic: 3 10 20 30 and 3 on its own line followed by three lines read identically. The count is validated before it sizes anything — a negative or missing n would otherwise be a huge allocation or an uninitialised loop bound. long long unless the prompt bounds the values.

Shape 2: a count, then N lines

int n;
std::cin >> n;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');   // finish the count's line
for (int i = 0; i < n; ++i) {
    std::string line;
    std::getline(std::cin, line);
    if (!line.empty() && line.back() == '\r') line.pop_back();       // a Windows-edited file
    // use line
}

The ignore is the whole difference between this and a bug: without it the first getline returns the empty remainder of the count's line. The \r check costs nothing and is the difference between a parser that works on files from every editor and one that mysteriously fails on the last field of every line.

Shape 3: tokens until the input ends

long long x;
while (std::cin >> x) { /* every token */ }

The loop ends on the first failed read — the end of the input, or a bad token; lesson 1's recovery loop tells the two apart when it matters.

Shape 4: lines until the input ends, each with structure

std::string line;
int lineNo = 0;
while (std::getline(std::cin, line)) {
    ++lineNo;
    if (line.empty()) continue;                 // blank lines are not records
    std::istringstream fields(line);
    std::string name;
    int qty;
    double price;
    if (!(fields >> name >> qty >> price)) {
        std::cout << "line " << lineNo << ": malformed\n";
        continue;
    }
    // use the record
}

This is the workhorse for records. Each line gets a fresh istringstream, so a failure is local: the outer getline loop is untouched and simply moves to the next line. The line number is counted here, at the only place that sees every line, and it is what a useful error message names.

Shape 5: a header, then records

A first line that describes the rest — 3 items, width=80, a column list — is Shape 2's count with extra fields, read with >> into as many variables as it has, followed by an ignore to the end of that line before the records begin. When a record's last field can contain spaces (42 3.5 Ada Lovelace), read the fixed fields with >> and the rest of the line with std::getline(fields >> std::ws, name) — the std::ws swallows the separator that >> stopped on.

Shape 6: a matrix

int rows, cols;
std::cin >> rows >> cols;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::vector<std::vector<long long>> m;
for (int r = 0; r < rows; ++r) {
    std::string line;
    if (!std::getline(std::cin, line)) { std::cout << "expected " << rows << " rows, got " << r << '\n'; return 0; }
    std::istringstream in(line);
    std::vector<long long> row;
    long long v;
    while (in >> v) row.push_back(v);
    if (static_cast<int>(row.size()) != cols) { std::cout << "row " << r + 1 << ": expected " << cols << " values, got " << row.size() << '\n'; return 0; }
    m.push_back(std::move(row));
}

Two templates exist and they differ in what they can check. The token-wise version (for r, for c: std::cin >> m[r][c]) is shorter and accepts any layout, which also means it cannot notice that row 2 had four numbers and row 3 had two — it just reads twelve tokens. The line-wise version above validates every row against cols and reports the first violation with its row number. Use the token version when the prompt guarantees the shape; use the line version when it is the program's job to check it. A row with a non-number stops the inner while early, so it reports as too few values, which is the right message.

Shape 7: records with a variable number of fields

std::string name;
int k;
while (std::cin >> name >> k) {
    std::vector<int> values(k);
    for (auto& v : values) std::cin >> v;
    // use name, values
}

When each record announces its own length, the count leads and the loop follows — the same as Shape 1, repeated. When the length is not announced (ada 3 5 9 / bob 7), the line is the record: Shape 4's getline plus an istringstream that reads tokens until the line runs out, and values.size() is the count. The second form is the one that can validate ("at least one value expected") and the one that survives a missing field without swallowing the next record's name as a number.

Validating and reporting

Three rules make an error message worth reading. Name the position — the line number or record index the program counted. Say what was expected and what was found, with the values. And decide the policy once: stop at the first error (return after printing it) or skip and continue (print, continue, and keep a count of bad lines for a summary). A judged program prints its report to std::cout because that is what is compared; a real tool sends diagnostics to std::cerr so the data output stays clean for the next program in the pipeline. Never trust the count over the data: after a "count then N lines" read, a getline that fails before N lines arrived is an error to report, not a silent zero. And check the whole line was consumed when the format is strict — after reading the expected fields, if (fields >> extra) succeeding means there was trailing junk.

Pitfalls

MistakeWhat happens
std::getline right after std::cin >> nThe first "line" is empty. ignore the rest of the count's line.
A matrix read token-wiseA short or long row is never noticed; the numbers shift into the wrong cells.
Parsing fields straight from std::cinOne bad field sticks the stream; every later record is lost. Parse a line copy.
Ignoring \rThe last field of each line carries a stray carriage return and compares unequal.
Trusting n over the dataA short input reads garbage into the missing rows; report the shortfall instead.

Key takeaways

  • >> for tokens when layout is irrelevant; std::getline when spaces are data or the line matters; both when a line has structure.
  • After a count read with >>, ignore(max, '\n') before the first getline; strip a trailing \r.
  • Parse each line in its own std::istringstream so a malformed line cannot stick std::cin.
  • A line-wise matrix reader can validate row lengths; a token-wise one cannot.
  • Error messages name the line, the expectation and the value; decide stop-or-skip once.

Common questions

How do I read input until EOF in C++?

Loop on the read itself: while (std::cin >> x) for whitespace-separated tokens or while (std::getline(std::cin, line)) for lines. Each loop stops at the first failed read — the end of the input, or a token that is not the expected type.

When should I use getline instead of cin >>?

Use >> when whitespace is only a separator and the line layout does not matter. Use std::getline when spaces are part of the data, such as a full name, or when which line a value is on matters. When a line has internal structure, getline it and parse the copy with a std::istringstream.

How do I split a line into fields in C++?

Read the line with std::getline, wrap it in a std::istringstream, and extract the fields with >>; if (!(fields >> name >> qty >> price)) reports a malformed line. A fresh stream per line keeps a bad field from putting std::cin into a failed state and losing every later record.

How do I read a matrix from input in C++?

Read the row and column counts, then either read rows * cols tokens with >> when the shape is guaranteed, or read each row with getline and parse it with an istringstream when the program must check it. Only the line-wise version can detect a short or long row and report its row number.

Why does the last field of each line fail to match?

The input was probably saved with Windows line endings, so every line read by getline ends in a stray carriage-return character that makes its last field compare unequal. Check whether line.back() is a carriage return and pop_back() it before parsing.

Exercises

N lines with spaces

Read an integer n, then n lines of text. A line may be empty and may have any amount of whitespace between and around its words. For line i (1-based) print <i>: words=<w> longest=<word> — w is the number of whitespace-separated words and longest the first word of maximal length — or <i>: empty when the line has no words. After the lines print total=<sum of all word counts>.

Read n with std::cin >>, discard the rest of that line with std::cin.ignore(...), then std::getline each line and split it with a std::istringstream. Strip a trailing \r if one is present.

Input: n, then n lines. Output: n lines, then the total.

3
the quick brown fox

  spaced   out

prints

1: words=4 longest=quick
2: empty
3: words=2 longest=spaced
total=6

Matrix with dimension validation

Read R C on the first line, then the matrix with one row per line. Read the rows line by line (std::getline then a std::istringstream) so the shape can be checked:

  • if the input ends before R rows were read, print error: expected <R> rows, got <k> and stop;
  • if a row does not contain exactly C integers, print error: row <i> has <k> values, expected <C> (1-based i, the first offending row) and stop;
  • otherwise print row <i>: <sum> for each row, then cols: <c1> <c2> ... <cC> with the column sums.

Use long long for the values and sums.

Input: R C, then up to R lines. Output: the report or the first error.

2 3
1 2 3
4 5 6

prints

row 1: 6
row 2: 15
cols: 5 7 9

and

2 3
1 2 3
4 5

prints error: row 2 has 2 values, expected 3.

In this module: Streams and files

← Streams in depth — state, recovery and the character API · File streams — open modes, RAII and reading back →