[[std::cin]] and [[std::cout]] handle input and output in C++ through a pair of stream objects that live in the standard library. [[std::cout]] writes to standard output, [[std::cin]] reads from standard input, and both are chainable objects that behave like a pipeline: you write one value after another and the stream passes them along in order. Understanding that chain is what makes formatted input and output feel natural instead of fussy.
Writing to standard output
The << operator inserts a value into a stream. Because it returns a reference to the stream, calls can be chained.
#include
int main() {
std::cout << "Recipe: " << "Lemon Drizzle Cake\n";
std::cout << "Servings: " << 8 << '\n';
std::cout << "Flour: " << 220.0 << " g\n";
std::cout << "Ready in " << 35 << " minutes\n";
return 0;
}The stream converts each value to text on the way through, so the integer 8 becomes the characters "8" and the double 220.0 becomes "220". The stream handles the formatting; you never convert anything by hand.
The newline can be written as '\n', which is a character literal, or as std::endl, which writes a newline and flushes the buffer. For ordinary output prefer '\n': flushing on every line is slow and rarely what you want.
Reading from standard input
The >> operator extracts a value from a stream into a variable. It skips leading whitespace, reads the value, and leaves the stream positioned right after it.
#include
#include
#include
int main() {
std::istringstream input("12 sour 250");
int servings = 0;
std::string flavour = "unknown";
double grams = 0.0;
input >> servings >> flavour >> grams;
std::cout << "servings: " << servings << "\n";
std::cout << "flavour: " << flavour << "\n";
std::cout << "grams: " << grams << "\n";
return 0;
}Reading three values from one stream, in order, with whitespace skipped between them:
servings: 12
flavour: sour
grams: 250The extraction above works exactly as it would with std::cin; only the source of the characters differs. An std::istringstream reads from a string in memory, which makes it ideal for testing and for parsing.
To read a whole line including spaces, use std::getline rather than >>.
#include
#include
#include
int main() {
std::istringstream input("Lemon Drizzle Cake\n12 servings, ready in 35 minutes\n");
std::string title;
std::string details;
std::getline(input, title);
std::getline(input, details);
std::cout << "title: " << title << "\n";
std::cout << "details: " << details << "\n";
return 0;
}The first >> would have stopped at the space in "Lemon Drizzle Cake". std::getline reads up to the newline and keeps the spaces.
The stream state is how you detect bad input
Every stream carries a state flag: eof when the end of input was reached, fail when extraction failed, and bad when something went seriously wrong. The critical rule is that a failed extraction leaves the target variable untouched, and the stream refuses to do anything more until you clear the failure.
#include
#include
int main() {
int servings = 0;
std::string word;
std::cout << "checking the stream state\n";
if (!(std::cin >> servings)) {
std::cerr << "error: servings must be a number\n";
std::cout << "falling back to a default of 4\n";
servings = 4;
} else {
std::cin >> word;
std::cout << "read " << servings << " servings and the word " << word << "\n";
}
std::cout << "done\n";
return 0;
}Wrapping the extraction in if (!(...)) is the standard idiom. The extra parentheses are required because ! binds more tightly than >>, so !std::cin >> servings would test the stream before extracting anything.
When you need to recover from bad input on the same stream, clear it and discard the rest of the line.
#include
#include
#include
int main() {
int servings = 0;
std::string remainder;
std::cout << "servings (default 4 if the input is not a number): ";
if (!(std::cin >> servings)) {
std::cin.clear();
std::cin.ignore(std::numeric_limits::max(), '\n');
std::cerr << "not a number, using the default\n";
servings = 4;
}
std::getline(std::cin, remainder);
std::cout << "using " << servings << " servings\n";
return 0;
}The ignore call throws away the offending characters up to the next newline, so the next read starts on a fresh line instead of choking on the same bad token.
Where cin and cout come from
std::cin and std::cout are global objects, declared in the <iostream> header, that are already connected to your program's standard input and standard output. When you redirect a program from the shell, the streams follow automatically: printing to std::cout goes to the terminal, to a file with > and into a pipeline with |. The same is true of std::cin, which reads from the keyboard or from whatever the shell feeds it.
That design is why a C++ program can be used as a filter in a shell pipeline without any special code, and why writing to std::cerr keeps diagnostics out of the data stream.
#include
int main() {
std::cout << "this line goes to standard output\n";
std::cerr << "this line goes to standard error\n";
std::clog << "this line is buffered diagnostics\n";
return 0;
}The three streams have different buffering behaviour. std::cout is buffered for speed, std::cerr is flushed after every write so that errors appear immediately, and std::clog is buffered like std::cout but reserved for logging.
Common mistakes when reading input
Three mistakes account for most input bugs.
- Forgetting to check the stream. An unchecked extraction that fails leaves the variable unchanged, and every later read fails too.
- Mixing
>>withstd::getlinecarelessly. After reading a number with>>, the newline is still in the stream, so the nextstd::getlinereads an empty line. Putstd::wsin front of thestd::getlineto skip that whitespace. - Expecting a number where text was typed. The extraction fails, the value is left alone, and a program that does not check will carry the stale value forward.
The rule that covers all three is the same: treat every extraction as a possible failure and decide explicitly what to do about it.
Formatting the output
Two manipulators from <iomanip> handle numbers. std::fixed forces a fixed number of decimal places and std::setprecision sets how many.
#include
#include
int main() {
std::cout << std::fixed << std::setprecision(2);
std::cout << "flour: " << 220.456 << " g\n";
std::cout << "sugar: " << 110.0 << " g\n";
std::cout << "ratio: " << 0.5 << "\n";
std::cout << std::setprecision(4) << std::fixed;
std::cout << "precise: " << 220.456 << "\n";
return 0;
}The output shows the formatting applied:
flour: 220.46 g
sugar: 110.00 g
ratio: 0.50
precise: 220.4560Because these manipulators change the stream's state, they affect every following output until changed again — C++ has no scoped formatting the way some languages do. The careful way to limit the damage is to save the old state, apply the change, and restore it.
#include
#include
int main() {
std::ios::fmtflags saved_flags = std::cout.flags();
std::streamsize saved_precision = std::cout.precision();
std::cout << "Default: " << 3.14159265 << "\n";
std::cout << "Scoped: " << std::setprecision(3) << std::fixed << 3.14159265 << "\n";
std::cout.flags(saved_flags);
std::cout.precision(saved_precision);
std::cout << "Default again: " << 3.14159265 << "\n";
return 0;
}The saved state is restored before the last line, so the default format comes back:
Default: 3.14159
Scoped: 3.142
Default again: 3.14159Quick reference
<<writes to a stream and>>reads from one; both are chainable.'\n'is cheaper thanstd::endl; only flush when you genuinely need to.std::getlinereads a whole line;>>stops at whitespace.- Check every extraction with
if (!(std::cin >> value))and handle the failure. - A failed extraction leaves the variable unchanged and latches the stream's failure flag.
- Recover with
std::cin.clear()followed bystd::cin.ignore(...)to drop the bad line. std::fixedandstd::setprecisioncontrol decimal places.
Try it yourself: write a program that prompts for a recipe name, a serving count and a scale factor, then prints the adjusted quantities. Run it and deliberately type letters where numbers are expected, and watch how the failure state behaves. Finally, change the prompts so that a bad value falls back to a default instead of ending the program.