Input, Output, and File Streams¶
A stream in C++ is an object that data flows through. std::cout is the stream connected to your console; std::cin is the stream that delivers what the user types; std::ifstream is a stream connected to a file you are reading.
The operators << and >> move data into and out of streams. Once you know the pattern with std::cout, the same shape works for every stream the standard library provides.
Console I/O¶
Three stream objects, all in <iostream>:
| Stream | Direction | Purpose |
|---|---|---|
std::cout |
output | Print to the console |
std::cin |
input | Read from the console (keyboard, usually) |
std::cerr |
output (error) | Print to the error stream |
#include <iostream>
int main() {
int number;
std::cout << "Enter a number: ";
std::cin >> number;
std::cout << "You entered " << number << "\n";
return 0;
}
<< reads "put this into the stream"; >> reads "extract from the stream into this variable." You can chain them; the operators return the stream itself so the next one can be applied immediately.
A note on
std::endlvs"\n": Both produce a newline.std::endlalso flushes the stream, forcing any buffered output to appear immediately. Flushing is expensive; in tight loops, prefer"\n". Reach forendlonly when you specifically want to flush.
Reading several values¶
Stream extraction (>>) skips whitespace, so reading several values is just chaining:
int a, b;
std::cout << "Enter two integers separated by a space: ";
std::cin >> a >> b;
std::cout << "Sum: " << (a + b) << "\n";
The user can type 3 5, 3<tab>5, or even press Enter between them; >> will pick up both.
When extraction fails¶
If the user types hello when you asked for an integer, >> fails silently; the stream enters an error state and subsequent extractions also fail. You can check the stream like a boolean:
Reading whole lines¶
>> stops at whitespace. To read an entire line (including spaces) use std::getline:
#include <string>
std::string name;
std::cout << "What is your name? ";
std::getline(std::cin, name);
std::cout << "Hello, " << name << "!\n";
File I/O¶
Files use the same operators. Three classes in <fstream>:
| Class | Direction | Purpose |
|---|---|---|
std::ifstream |
input | Read from a file |
std::ofstream |
output | Write to a file |
std::fstream |
both | Read and write |
Reading a file line by line¶
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream in("readings.txt");
if (!in) {
std::cerr << "Could not open readings.txt\n";
return 1;
}
std::string line;
while (std::getline(in, line)) {
std::cout << line << "\n";
}
// No explicit close needed, RAII closes the file when `in` goes out of scope.
}
The if (!in) check uses the stream's bool conversion: a "good" stream is truthy, a stream that failed to open or has hit an error is falsy.
std::ifstream is a great example of RAII in action: opening the file in the constructor, closing it in the destructor. You do not have to remember to call close(); it happens automatically, even if an exception is thrown mid-function.
Writing a file¶
#include <fstream>
std::ofstream out("results.txt");
out << "Mean: " << mean << "\n";
out << "Std dev: " << stddev << "\n";
// closed automatically when `out` goes out of scope
By default std::ofstream truncates the file; any previous contents are lost. To append instead:
Printing your own types¶
std::cout << myObject; works for built-in types and most standard library types. For your own classes, you teach the stream how to print them by overloading operator<<:
#include <iostream>
struct Vector3 { // a struct is just a class with public members by default
double x, y, z;
};
std::ostream& operator<<(std::ostream& os, const Vector3& v) {
os << "Vector3(" << v.x << ", " << v.y << ", " << v.z << ")";
return os;
}
int main() {
Vector3 v{1.0, 2.0, 3.0};
std::cout << v << "\n"; // prints: Vector3(1, 2, 3)
}
Two things to notice:
- The first parameter is
std::ostream&(the base class ofstd::cout,std::ofstream, etc.); so the same overload works with any output stream. - The function returns the stream so that
<<calls can be chained.
The same pattern with std::istream& and >> lets you parse your own type from input.
Formatting¶
For most output, default formatting is fine. When it is not, the <iomanip> header has manipulators that change how subsequent values are printed:
#include <iomanip>
#include <iostream>
double pi = 3.14159265;
std::cout << std::fixed << std::setprecision(2) << pi << "\n"; // 3.14
std::cout << std::setw(10) << 42 << "\n"; // " 42"
std::cout << std::hex << 255 << "\n"; // ff
Manipulators are "sticky": once you set them on a stream, they stay set until you change them. If you only need formatting for a single value, save and restore — or, much more cleanly, use std::format from <format>:
#include <format>
std::cout << std::format("{:.2f}\n", pi); // 3.14
std::cout << std::format("{:>10}\n", 42); // right-aligned in 10 columns
std::cout << std::format("{:#x}\n", 255); // 0xff
The format string follows Python-style placeholders: {} for the next argument, with optional spec after :. Prefer this over manipulators when you only need one formatted value; no sticky state to clean up.
printf-style formatting from <cstdio> is also available, and a common choice in embedded code.
Summary¶
<<writes to a stream;>>reads from one. Both chain.std::cout,std::cin,std::cerrare the console streams;std::ifstream/std::ofstreamare file streams.- Prefer
"\n"tostd::endlunless you specifically want to flush. std::getlinereads a whole line including spaces.- File streams close themselves automatically when they go out of scope (RAII).
- Define
operator<<for your own classes to make them printable.