std::cout, std::cin, and std::format
Input and output in C++ are handled through streams — objects that represent a flowing sequence of data. std::cout (character output) sends data to the terminal. std::cin (character input) reads data from the keyboard. The << operator sends data into a stream; >> extracts data from a stream. The stream abstraction is powerful because the same << operator works for files, strings, and the network — you learn it once and reuse the pattern everywhere.
Output with std::cout
The << operator is left-to-right associative, so you can chain multiple insertions in one statement. Each argument is converted to text and sent to the terminal. "\n" moves to the next line; std::endl does the same but also flushes the buffer (forces any buffered output to appear now). Prefer "\n" in loops for performance.
#include <iostream> int age = 25; double gpa = 3.7; std::string name = "Alice"; // Chained output: std::cout << "Name: " << name << ", Age: " << age << "\n"; // Output: Name: Alice, Age: 25 // endl vs \n: std::cout << "Line one" << std::endl; // flushes buffer std::cout << "Line two" << "\n"; // faster, no flush // Numbers are formatted automatically: std::cout << gpa << "\n"; // 3.7
Output formatting: width, precision, and alignment can be controlled with IO manipulators from <iomanip>. However, the modern approach is std::format (C++20), covered below.
#include <iomanip> double pi = 3.14159265; std::cout << std::fixed << std::setprecision(2) << pi; // 3.14 std::cout << std::setw(10) << "hello"; // right-aligned in 10 chars
Input with std::cin
The >> extraction operator reads from the input stream into a variable. For numbers, it skips whitespace and reads until a non-numeric character. For strings, it reads one whitespace-delimited word. To read an entire line including spaces, use std::getline(std::cin, str).
#include <iostream> #include <string> int age; std::cout << "Enter your age: "; std::cin >> age; double price; std::cout << "Enter price: "; std::cin >> price; // Read multiple values in one statement: int x, y; std::cin >> x >> y; // reads two integers separated by whitespace // Read a full line (including spaces): std::cin.ignore(); // discard leftover newline from previous >> read std::string line; std::getline(std::cin, line);
Input validation: if the user types something that doesn't match the expected type, std::cin enters a fail state. All subsequent reads produce zero/empty without waiting. Always check std::cin.fail() or test the stream directly when robustness matters.
int n;
std::cin >> n;
if (!std::cin) { // or: if (std::cin.fail())
std::cout << "Invalid input\n";
std::cin.clear(); // clear the error flag
std::cin.ignore(1000, '\n'); // discard bad input up to newline
}Formatted strings with std::format (C++20)
C++20 introduced std::format — a type-safe, Python/Rust-style string formatting function. It uses curly-brace placeholders ({}) that are filled with the provided arguments, producing a formatted std::string. It is cleaner than printf (type-safe) and more convenient than chained << operators for complex formatting.
#include <format> // C++20
std::string s = std::format("Hello, {}! You are {} years old.", "Alice", 25);
// s = "Hello, Alice! You are 25 years old."
// Directly to cout with std::print (C++23) or format + cout:
std::cout << std::format("Pi ≈ {:.4f}\n", 3.14159); // Pi ≈ 3.1416
// Format specifiers:
std::cout << std::format("{:>10}", "right"); // right-aligned in 10 chars
std::cout << std::format("{:<10}", "left"); // left-aligned
std::cout << std::format("{:^10}", "center"); // centered
std::cout << std::format("{:08d}", 42); // "00000042"
std::cout << std::format("{:.2f}", 3.14159); // "3.14"
std::cout << std::format("{:+}", 42); // "+42" (always show sign)If your compiler does not yet support std::format (requires GCC 13+, Clang 14+, MSVC 19.29+), the fmt library (fmtlib) provides the same API as a third-party dependency, and was the reference implementation for the standard.
std::cerr and std::clog
Beyond std::cout, the standard library provides two other output streams. std::cerr writes to standard error (stderr) and is always unbuffered — use it for error messages that must appear immediately. std::clog is buffered standard error — use it for diagnostic logging.
// Errors to stderr — separate from normal output:
if (!file.is_open()) {
std::cerr << "Error: could not open file\n";
return 1;
}
// Redirect stdout to a file while keeping errors on the terminal:
// $ ./myprogram > output.txt — cerr still appears on terminalKey rules to remember
Prefer "\n" over std::endl in performance-sensitive output
endl flushes the output buffer every time. \n just appends a newline. Flushing on every line is expensive inside loops.
Use std::getline for reading a full line; plain >> stops at the first space
After a >> read, a newline remains in the buffer. Call std::cin.ignore() before std::getline to discard it.
Check std::cin after reading to detect invalid input
If the user types letters when you expect an integer, cin enters a fail state. Call cin.clear() and cin.ignore() to recover.
Use std::format (C++20) for complex formatted output
It is type-safe (unlike printf), cleaner than chained <<, and supports all the common format specifiers (width, precision, alignment, sign).
Send error messages to std::cerr, not std::cout
Users can redirect stdout to a file with > while keeping stderr visible on the terminal. Mixing errors into stdout makes both unusable.