C++ Module 19 – C++ for DSA and competitive programming
Fast C++ input and output for online judges
Why C++ streams read slowly as they start, the two lines that fix it, why std::endl in a loop costs a flush per line, and when an interactive problem needs one.
What you will learn
- Configure the C++ streams for fast input without breaking them
- Avoid a flush per line in output loops
- Handle interactive problems by flushing after every query
- Choose a reader and a writer from measurements on both standard libraries
Before you start
What you’ll learn · Before you start
What you will learn
- Configure the C++ streams for fast input without breaking them
- Avoid a flush per line in output loops
- Handle interactive problems by flushing after every query
- Choose a reader and a writer from measurements on both standard libraries
Before you start
On this page
Fast C++ input on a judge comes down to two lines at the start of main: std::ios::sync_with_stdio(false); and
std::cin.tie(nullptr);. In the measured run below, the two lines made GCC’s cin read a million integers about
twenty times faster. As the streams start, every read through cin is kept in step with C’s scanf and getchar,
and it first flush: To force the text a stream is holding in its buffer out to the screen or the file at once. std::endl flushes after its line break; '\n' alone does not, so the stream can write many lines together. More in “Console I/O in C++: cin, cout, print and println” cout, because the two streams are tied. The first line lets the C++
streams buffer on their own; the second removes the flush.
Output for online judges has a rule of its own: end lines with '\n', not std::endl, which also flushes the stream
on every line. A problem in which the judge's program talks to yours while it runs: it reads each query your program prints, answers it, and waits for the next one, instead of giving all of the input at the start. are the one exception to both rules: the judge waits for each of your queries before it
answers, so there you flush after every query.
Two defaults make cin slow as it starts
The C++ standard makes cin, cout and the other standard streams: The three channels a console program starts with: standard input, which std::cin reads, and standard output and standard error, which std::cout and std::cerr write. The shell can connect each one to the terminal, a file or a pipe. More in “Console I/O in C++: cin, cout, print and println” work together with C’s stdin and stdout
unless a program says otherwise. A program can then mix std::cin >> x with scanf and see the input in the right
order, because each C++ operation goes straight through to the C stream. That safety costs speed: cppreference notes
that the synchronised streams are, in practice, unbuffered.
The second cost is the tie. The standard says that after cin is set up, cin.tie() returns &cout, and before any
read, a stream flushes the stream it is tied to. That is what makes a prompt such as “Enter n:” appear before the
program waits for you, and it means a program that reads a number and prints a line, a million times, also flushes
cout a million times.
What one read with cin does before and after the two template lines, in libstdc++
Text description of the diagram
Two columns show the steps of one read, cin >> x.
As the streams start: first cout is flushed, because cin is tied to cout; then the characters are taken through C's standard input, kept in step with scanf and getchar, so that C and C++ input can be mixed.
After the two lines, std::ios::sync_with_stdio(false) and std::cin.tie(nullptr): there is no flush before the read, and the number is parsed from cin's own buffer, which is refilled from the input in large blocks.
In libc++, the library of Apple clang, cin stayed slow after the two lines in the version measured here.
The left column is the path of every read as the streams start, and the right column the path after the two lines that the next section measures.
Checkpoint
Check: Why cin starts slow
Two lines make GCC’s cin about twenty times faster
This program reads a million integers in three ways and reports the CPU time each took, which other programs on the computer hardly change. Every time on this page was measured on an Apple M5 Pro under macOS 26:
// read_three_ways.cpp: reads n integers and prints their sum and the CPU time it took, in one of three ways:
// ./read default std::cin as the streams start
// ./read tuned std::cin after the two lines of a contest template
// ./read scanf C's scanf
#include <cstdio>
#include <ctime>
#include <iostream>
#include <string_view>
int main(int argc, char* argv[]) {
const std::string_view how = argc > 1 ? argv[1] : "default";
if (how == "tuned") {
std::ios::sync_with_stdio(false); // C++ streams may buffer on their own, apart from C's stdio
std::cin.tie(nullptr); // reading no longer flushes cout first
}
const std::clock_t start = std::clock(); // CPU time, which other programs hardly change
long long n = 0, sum = 0;
if (how == "scanf") {
if (std::scanf("%lld", &n) != 1) return 1;
for (long long i = 0, x = 0; i < n && std::scanf("%lld", &x) == 1; ++i) sum += x;
} else {
std::cin >> n;
for (long long i = 0, x = 0; i < n && std::cin >> x; ++i) sum += x;
}
const double ms = 1000.0 * static_cast<double>(std::clock() - start) / CLOCKS_PER_SEC;
std::printf("%-7s %lld numbers, sum %lld, %5.0f ms\n", how.data(), n, sum, ms);
} from session import run
# A million integers read three ways with each standard library: Apple clang uses libc++, GCC uses libstdc++.
run("""
python3 gen_ints.py
clang++ -std=c++23 -O2 read_three_ways.cpp -o read && ./read default < ints.txt && ./read tuned < ints.txt && ./read scanf < ints.txt
g++-16 -std=c++23 -O2 read_three_ways.cpp -o read-gcc && ./read-gcc default < ints.txt && ./read-gcc tuned < ints.txt && ./read-gcc scanf < ints.txt
""") Output
$ python3 gen_ints.py wrote ints.txt: 1000000 numbers, sum 260585712848 $ clang++ -std=c++23 -O2 read_three_ways.cpp -o read && ./read default < ints.txt && ./read tuned < ints.txt && ./read scanf < ints.txt default 1000000 numbers, sum 260585712848, 1668 ms tuned 1000000 numbers, sum 260585712848, 1625 ms scanf 1000000 numbers, sum 260585712848, 107 ms $ g++-16 -std=c++23 -O2 read_three_ways.cpp -o read-gcc && ./read-gcc default < ints.txt && ./read-gcc tuned < ints.txt && ./read-gcc scanf < ints.txt default 1000000 numbers, sum 260585712848, 1279 ms tuned 1000000 numbers, sum 260585712848, 64 ms scanf 1000000 numbers, sum 260585712848, 114 ms
This output changes from run to run: CPU times change a little from run to run and a lot from one computer to another
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 three_ways_session.py
With GCC’s libstdc++, the library of every GCC-based judge, the two lines took cin from more than a second to well
under a tenth of one, and scanf was fast too. Apple clang’s libc++ is the exception: its cin stayed slow with the
two lines, while scanf was as fast there as with GCC. Fast C++ input on a GCC judge therefore needs nothing more
than the two lines. Keep them in your template, and when you work on a Mac, measure your reading code with GCC, or
read with scanf, before you decide that a solution is too slow.
The two lines come with one rule: once the streams are no longer in step, do not mix C and C++ output on the same
stream, or C and C++ input. Call both lines before any input or output: if sync_with_stdio comes after the first
read or write, the standard leaves its effect to each library. This program breaks the rule on purpose:
// mixed.cpp: after sync_with_stdio(false), cout and printf have separate buffers, so lines can leave out of order.
#include <cstdio>
#include <iostream>
int main() {
std::ios::sync_with_stdio(false);
std::cout << "1: cout\n";
std::printf("2: printf\n");
std::cout << "3: cout\n";
std::printf("4: printf\n");
} from session import run
# mixed.cpp with each library, its output written to a file as a judge would, then shown.
run("""
clang++ -std=c++23 -O2 mixed.cpp -o mixed && ./mixed > out.txt && cat out.txt
g++-16 -std=c++23 -O2 mixed.cpp -o mixed-gcc && ./mixed-gcc > out-gcc.txt && cat out-gcc.txt
""") Output
$ clang++ -std=c++23 -O2 mixed.cpp -o mixed && ./mixed > out.txt && cat out.txt 1: cout 2: printf 3: cout 4: printf $ g++-16 -std=c++23 -O2 mixed.cpp -o mixed-gcc && ./mixed-gcc > out-gcc.txt && cat out-gcc.txt 1: cout 3: cout 2: printf 4: printf
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 mixed_session.py
With libstdc++, the four lines left the program as 1, 3, 2, 4: each stream wrote its own buffer when the program
ended, cout’s first. libc++ kept the order here, and code that relies on that works with one library only.
Key idea
Put both lines before any input or output, then never mix cin with scanf, or cout with printf.
Checkpoint
Check: What the two template lines change
std::endl flushes every line, a newline does not
std::endl writes a newline and then flushes the stream, and a flush hands the buffer to the operating system, which
costs far more than storing one character. In a loop that prints a million lines, that is a million separate writes.
'\n' only stores the newline; the stream is flushed when its buffer fills and when the program ends normally, so
nothing is lost. Output for online judges should therefore use '\n', or printf, which is buffered too when its
output goes to a file.
Step through the same loop both ways, and count the writes that reach the file:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- A newline is stored. With '\n', each line is stored in cout's buffer. Storing one more character costs almost nothing, and nothing reaches the file yet.
- Lines pile up. The loop goes on, and the buffer collects line after line. The operating system has not been asked to do anything so far.
- One write for many lines. When the buffer is full, the stream hands all of its lines to the operating system in one write, then starts filling the buffer again.
- Nothing is lost at the end. When the program ends normally, the stream flushes what is left. So '\n' loses no output; it only decides when the lines are written.
- std::endl flushes. std::endl writes the newline and then flushes the stream. Each line goes to the operating system at once, on its own, before the next line is printed.
- A million writes. In a loop of a million lines, std::endl makes a million separate writes, and each costs far more than storing a character. Use '\n' unless a line must leave now.
Both loops wrote the same lines; only the number of writes differed, one per line with std::endl and one per full
buffer with a newline.
Checkpoint
Check: std::endl against a newline
An interactive judge waits for every query you flush
In an interactive problem the judge reads each query of your program, answers it, and only then expects the next
one. A query that is still in your program’s buffer never reaches the judge, so both programs wait for each other
until the time limit ends. Flush after every query: std::flush flushes cout without writing anything,
std::endl writes a newline and flushes, and fflush(stdout) does the same for printf. Keeping cin tied to
cout also works, because every read then flushes the query for you.
Follow the first query of an interactive problem, once without a flush and once with one:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- The query is stored. Your solution prints its first query with '\n' and no flush. The line goes into cout's buffer, inside your own program, and nothing reaches the judge.
- Your program waits. Next the solution reads the judge's answer, so it stops and waits for input.
- The judge waits too. The judge answers only a query it has read, and it has read nothing. Both programs wait for each other until the time limit ends the run.
- Flush the query. With std::flush after the query, or std::endl, or fflush(stdout) after printf, the buffer is handed over at once, and the judge reads the query.
- The answer comes back. The judge answers, and the read in your solution returns with it. Every query needs its flush before the next read.
- A tied cin flushes for you. If cin is still tied to cout, every read flushes cout first, so the query leaves before your program waits, without a flush of your own.
Ordinary output wants as few flushes as possible; an interactive query needs its flush every time, or the judge never sees it.
Checkpoint
Check: Flushing in interactive problems
Practise: reading, writing and flushing
Test the two defaults, the two template lines, line endings and interactive flushes here. Your least sure idea is asked about first, and every option carries a reason.
Practice that adapts to you
Practise this lesson
9 questions about 7 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Five readers and four writers, measured with both libraries Pro: opens with a Pro, Premium or Ultimate pass
How fast a reader is depends on the standard library, and the fastest ways skip the streams entirely. This part measures five readers on a million integers and four ways to write a million lines, with libc++ and with libstdc++.
In this part:
- Five readers on the same million integers, measured
- Why tuned cin stayed slow with libc++, and what to use on a Mac
- Writing a million lines: std::endl against a newline, measured
- Choosing a reader and a writer
4 runnable examples (C++, Python) · about 11 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Interactive problems, reproduced with a judge you can run Pro: opens with a Pro, Premium or Ultimate pass
In an interactive problem the judge answers each query only after it has read it, so a query that stays in a buffer stops both programs. This part runs a small judge of the same kind on your computer, reproduces the stall and its two fixes, and ends with a timed drill.
In this part:
- A judge you can run, and the dialogue it expects
- The missing flush, reproduced, and the template line that causes it
- Exercise: a timed drill with two million numbers
1 diagram · 4 runnable examples (C++, C++ (guess.cpp), C++ (guess_lost.cpp), C++ (guess_tied.cpp), Python, Python (check_drill.py), Python (gen_drill.py)) · about 7 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Interview questions
-
Fresher · Warm-up
What is the difference between std::endl and '\n', and when does the difference matter?
Both end the line, but std::endl also flushes the stream: it writes '\n' and then calls flush(), which hands the buffer to the operating system. '\n' only stores the character; the stream is flushed when its buffer is full, when you flush it yourself and when the program ends normally. The difference matters when output goes to a file or a pipe, as it does on a judge: with std::endl, each of a million lines becomes its own write to the operating system, while '\n' lets the stream hand over many lines in one write. For a few lines it does not matter, and in an interactive problem the flush is exactly what you need, though std::flush says so more clearly.
-
Fresher to mid
Your O(n log n) solution for n = 10^6 exceeds a 2-second time limit on a GCC judge, and a profile on your Mac shows most of the time inside std::cin. How do you confirm that reading is the problem, and what do you change, with the numbers you expect?
-
Fresher to mid
An interactive solution works when you type the judge's answers by hand in a terminal, but on the judge it runs out of time on the first test without the judge seeing a single query. Explain both observations and fix the code.
-
Mid to senior
A problem asks for up to 2 × 10^6 numbers, one per line, under a tight time limit, and the judge uses GCC. Design the output code, estimate what each choice costs, and say what you would measure before submitting.
Key takeaways
- Start
mainwithstd::ios::sync_with_stdio(false);andstd::cin.tie(nullptr);for judges that use libstdc++. - After the first line, never mix
cinwithscanf, orcoutwithprintf. - End lines with
'\n';std::endlflushes every time. - In an interactive problem, flush after every query.
References
- Working Draft, Programming Languages: C++ (N4950) (ISO/IEC JTC1/SC22/WG21)
- std::ios_base::sync_with_stdio (cppreference.com)
- std::basic_ios::tie (cppreference.com)
- std::endl (cppreference.com)
- std::from_chars (cppreference.com)
- Reading from stdin is 10x slower than libstdc++ (LLVM issue 21566) (LLVM Project)
- [libc++] Optimize standard streams with sync_with_stdio(false) (pull request 209161) (LLVM Project)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress