Every C++ program eventually needs to talk to the outside world: print a result, read a value the user typed, or report something that went wrong. The standard library handles all of this through stream objects defined in <iostream>. This lesson covers the four common streams, the operators that drive them, line-based input, formatting, and the bugs that come up often.
Including <iostream> gives you four objects in the std namespace, each tied to a different communication channel:
| Stream | Direction | Channel | Buffered? | Use for |
|---|---|---|---|---|
std::cin | Input | Standard input (stdin) | Yes | Reading from the keyboard or piped input |
std::cout | Output | Standard output (stdout) | Yes | Normal program output |
std::cerr | Output | Standard error (stderr) | No (unbuffered) | Error messages, urgent diagnostics |
std::clog | Output | Standard error (stderr) | Yes | Logging, non-urgent diagnostics |
cerr and clog both write to the same destination (stderr), but they behave differently. cerr is unbuffered, meaning every character is pushed out immediately. clog buffers its output the same way cout does, so writes are batched until the buffer fills or an explicit flush happens. The distinction matters and is covered below.
In a normal terminal, all three lines show up in the same window because stdout and stderr are both connected to the screen. The difference becomes visible after redirecting one of them, which is the point of having separate streams.
Running the program above as ./store > out.txt sends only the first line into out.txt. The two stderr lines still print to the terminal. That separation lets shell scripts and CI systems keep error logs apart from normal output.
std::cout and <<std::cout is the standard output stream. Values get pushed into it with the << operator, called the stream insertion operator when used with a stream on the left. std::cout << x reads as "push x into the cout stream."
The operator returns the stream itself, which is what makes chaining possible:
A single statement like std::cout << "Quantity: " << quantity << ", Price: $" << price is four chained calls. Each << writes the value on its right and returns the stream so the next << has something to write into. That's why one line can mix strings, integers, and doubles without any explicit formatting calls.
Any built-in type and most standard-library types (std::string, for example) work directly with cout. For a custom class, << has to be defined, which is what the Operator Overloading section covers.
std::endl vs '\n'Both std::endl and the character '\n' move the cursor to the next line. The difference is what else they do.
std::endl writes a newline and flushes the stream's buffer. Flushing forces any pending output to be written out immediately.'\n' (or "\n" inside a string) writes a newline and nothing else. The buffer keeps holding whatever it had.For one-line programs, the difference is invisible. The buffer gets flushed when the program exits anyway. The difference matters in tight loops.
Writing std::endl inside the loop would call flush 10,000 times. Each flush goes through a system call to the operating system, which is much more expensive than appending bytes to an in-memory buffer.
std::endl flushes the output buffer on every call. In hot loops that print thousands of lines, replace it with '\n' and flush once at the end, or rely on automatic flushing at program exit.
The rule of thumb: use '\n' by default, use std::endl only when the output needs to appear immediately (for example, when prompting the user and waiting for a response).
std::cin and >>std::cin reads from standard input. Values come out with >>, the stream extraction operator. std::cin >> x reads as "pull a value out of cin and store it in x."
Sample run (user input is the value after each prompt):
>> is token-based, which is the most important fact about it. Extracting into a variable makes cin skip leading whitespace (spaces, tabs, newlines), read characters until the next whitespace, and convert the result to the requested type. The whitespace that stopped the read stays in the buffer for the next operation.
That last detail is why >> cannot read "Wireless Mouse" into a std::string. The space between the words stops the extraction. Running the program above with Wireless Mouse as input would set product to "Wireless" and try to read Mouse as the quantity, which fails. std::getline fixes this, covered below.
Like <<, the >> operator returns the stream, so extractions can be chained:
Sample run:
Whitespace between tokens is treated the same whether it's a space or a newline. Three values on three separate lines work as well as three values on one line.
std::getlineFor input that might contain spaces (a customer name, a shipping address, a product description), >> won't do. The standard solution is std::getline:
Sample run:
std::getline(std::cin, line) reads everything up to and including the next newline. The newline itself is consumed (so the next read starts fresh) but is not stored in line. The whole rest of the input line, spaces and all, becomes part of the string.
Two arguments matter here: the stream to read from (std::cin) and the string to fill (customerName). A third optional argument changes the delimiter from newline to something else, but the two-argument form is the usual choice for keyboard input.
>> Then getline BugMixing >> and std::getline is the single most common C++ I/O mistake. The bug looks like this:
Broken code:
Sample run:
The program never gives the user a chance to type the name. Here's why: cin >> quantity reads 3 and stops at the newline that the user pressed Enter to send. That newline stays in the input buffer. The next std::getline reads "everything up to the next newline," which is right there in the buffer, so it returns an empty string immediately.
Fix: drain the leftover newline before the getline. The cleanest tool is std::cin.ignore(...).
Sample run:
std::cin.ignore(n, c) discards up to n characters or up to and including the first occurrence of character c, whichever comes first. Passing std::numeric_limits<std::streamsize>::max() for n (which lives in <limits>) means "no upper limit," so the only stop condition is hitting the newline. After the ignore call, the buffer is fresh and getline does the right thing.
The >> operator is overloaded for all the built-in types and std::string, so the same syntax works regardless of what's being read:
Sample run:
One thing to note about char: extracting a char reads a single non-whitespace character, not a single character including whitespace. To read a space or a tab, use std::cin.get(ch) instead, which reads the next character regardless.
For bool, the default text representation is 0 or 1. Typing true and false instead requires the std::boolalpha manipulator, covered in the formatting section.
good, fail, bad, eofEvery stream tracks a small set of state flags that report whether the last operation went well. The four query methods cover the common cases:
| Method | Returns true when |
|---|---|
cin.good() | No error flags are set. The stream is healthy. |
cin.fail() | The last operation failed to extract a value (for example, asking for an int but the user typed abc). |
cin.bad() | A serious I/O error happened (rare; usually means the underlying device went wrong). |
cin.eof() | The stream reached end-of-file. No more input is coming. |
The stream can also be tested directly in an if or while condition. A stream evaluates to true when it's healthy and false when any error flag is set:
Sample run with valid input:
Sample run with invalid input:
The expression std::cin >> quantity returns the stream, which converts to a boolean for the if check. When the extraction fails, the stream's failbit is set, the boolean conversion gives false, and the else branch runs.
Once a stream is in a failed state, every subsequent operation does nothing until the error is cleared. Two calls work together to recover:
std::cin.clear() resets the error flags so the stream is usable again.std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') throws away the offending input that caused the failure.Both are needed. clear() alone leaves the bad characters in the buffer, so the next read fails the same way. ignore() alone runs into the failed state and does nothing.
Sample run:
This pattern (prompt, read, validate, clear-and-ignore on failure, retry) makes a reliable interactive prompt in C++. The diagram below walks through it:
clear() resets the flags, ignore(...) discards the leftover garbage, and the loop tries again. Without that cleanup, the program would spin printing the error forever because the same bad characters would re-trigger the failure on every iteration.
std::cerr and std::clogBoth cerr and clog write to stderr, the same channel used by error messages. The split between them comes down to buffering.
std::cerr is unbuffered. Every write goes out to the OS immediately. That's the right choice for a fatal error: even if the program crashes in the next microsecond, the error message has already been written.
std::clog is buffered like std::cout. Writes accumulate in memory and flush when the buffer fills or on an explicit flush. That's better for high-volume logging where each individual message isn't urgent, because the buffered version avoids the cost of a system call per write.
Output (to terminal, with stderr and stdout interleaved):
Running this program as ./order > orders.log 2> errors.log puts the Order received line in orders.log and the WARNING line in errors.log. The split shows up only when redirected.
A useful rule: log warnings and unrecoverable errors to cerr, log routine diagnostic information to clog, and use cout for the actual output the program is supposed to produce. Returning a non-zero exit status (return 1;) is the matching convention for signaling failure to whatever script ran the program.
<iomanip>Out of the box, cout prints numbers with sensible defaults but no control over width, alignment, or precision. The <iomanip> header provides a set of manipulators that get inserted into the stream to change how the next values are formatted.
| Manipulator | What it does |
|---|---|
std::setw(n) | Sets the minimum field width for the next value to n characters. |
std::setfill(c) | Sets the character used to pad short values to the field width. Defaults to space. |
std::left / std::right | Left- or right-aligns values within their field. Default is right. |
std::setprecision(n) | Sets the number of digits used for floating-point output. |
std::fixed | Print floats in fixed-point notation. setprecision now means digits after the decimal. |
std::scientific | Print floats in scientific notation (e.g., 1.234e+02). |
std::defaultfloat | Restore the default floating-point format. |
std::boolalpha / std::noboolalpha | Print bool as true/false or 1/0. |
std::hex, std::dec, std::oct | Print integers in base 16, 10, or 8. |
std::showpos / std::noshowpos | Print a leading + for positive numbers, or not. |
Most manipulators are sticky: they keep their setting until changed. The one exception is std::setw, which resets to zero after the very next value is written. That's the right behavior for column layouts.
Lining up columns is the primary use case for these manipulators. A printed receipt that mirrors what a real store would output:
A few things are happening here. std::fixed switches floats into fixed-point mode so the output has exactly two digits after the decimal. std::setprecision(2) sets how many of those digits. Both are sticky, so setting them once at the top makes every subsequent float follow. std::setw(20) applied right before "Wireless Mouse" reserves a 20-character field, and std::left left-aligns the name inside it. std::right then aligns the numeric columns to the right edge of their fields.
boolalpha and the base manipulators are smaller features but show up often enough to mention:
boolalpha is handy for printing a human-readable status. hex, dec, and oct come up in low-level work (memory addresses, bit patterns), but decimal is the common case. Like other formatting manipulators, all four are sticky, so switch back when done.
std::flush and Output Bufferingstd::cout and std::clog are line-buffered when connected to a terminal and block-buffered when connected to a file or pipe. That means output might sit in memory for a while before it reaches the screen or the disk. Three things force a flush:
std::endl, std::flush, or by reading from cin (which auto-flushes cout by default).The last point is why prompts usually work without endl: a std::cin >> call flushes anything pending on cout first. Still, it's safer to write std::flush or std::endl after a prompt so the prompt appears before the program blocks waiting for input.
Each flush is a system call. Writing std::endl inside a million-iteration loop spends most of its time talking to the OS instead of doing useful work. Use '\n' for newlines and flush only when output ordering matters.
using namespace std;Many tutorials drop the std:: prefix by writing using namespace std; at the top. That works, but it has real downsides in larger projects: it pulls every name from the standard library into the local scope, which can collide with custom names or names from other libraries.
This lesson keeps the explicit std:: prefix for clarity. The Namespaces section covers the trade-offs in depth, including when using namespace std; is acceptable, when it's risky, and the safer alternatives (using std::cout;, scoped using inside a function, and so on).
sync_with_stdio for Competitive ProgrammingBy default, C++'s cin/cout stay synchronized with C's printf/scanf so they can be mixed freely in the same program. That synchronization costs performance. Without mixing C and C++ I/O, it can be turned off:
Sample run:
sync_with_stdio(false) decouples C++ streams from C stdio buffers. cin.tie(nullptr) stops cin from flushing cout before each input operation. Combined, they often make cin/cout competitive with scanf/printf on large inputs.
Use this only when the C and C++ I/O facilities won't be mixed. For everyday application code, leave the defaults alone. The speedup matters in tight read loops over millions of values, which is mostly a competitive programming concern.
printf and scanf from <cstdio> are the C-style alternatives. They still work in C++, and they appear in older code or on competitive programming sites. This lesson doesn't cover them. The C Interoperability section in Advanced Topics has the details.
Tying everything together, a small program that takes a customer's information, builds a receipt, and writes a warning to cerr when stock is low:
Sample run:
This one program uses getline for the multi-word inputs, >> for the numeric inputs, cerr for the stock warning, std::fixed plus std::setprecision for two-decimal currency, and std::setw with std::left/std::right to line up the columns.
10 quizzes