By default, cout prints numbers however it sees fit. A price of 12.5 appears as 12.5 instead of 12.50, a long decimal shows six significant digits, and nothing lines up in columns. That's fine while you're experimenting, but real programs, from receipts to reports to game scoreboards, need tidy, predictable output.
C++ formats output with manipulators from the <iomanip> header. You send them into a stream just like values: cout << fixed << setprecision(2) << price;. They control decimal places, column widths, alignment and padding.
The same stream ideas work on strings. A string stream lets you build text with << exactly as you would with cout, or read numbers and words out of a line of text with >>. In this lesson you'll format a neat table, build strings piece by piece, and split and parse text such as a line from a CSV file.
Decimal places
#include <iomanip>
double price = 12.5;
cout << fixed << setprecision(2) << price << endl; // 12.50fixedswitches to normal decimal notation, and makessetprecision(n)mean n digits after the decimal point.- Without
fixed,setprecision(n)means n significant digits in total, which is rarely what you want for money. - These settings are sticky: they stay in effect for every later number on that stream until you change them.
- Values are rounded, not cut off:
2.345with two decimals shows2.35or2.34depending on how the binary value is stored, so don't rely on exact halves.
Width, alignment and fill
| Manipulator | Effect | Sticky? |
|---|---|---|
setw(n) | The next value takes at least n characters | No, only the next value |
left / right | Align within the width | Yes |
setfill('0') | Pad with this character instead of spaces | Yes |
boolalpha | Print true/false instead of 1/0 | Yes |
Numbers and text are right-aligned by default. Because setw only applies to the next item, repeat it before every value in a table row. setw never cuts a value short: a value longer than the width is printed in full.
Building strings with ostringstream
#include <sstream> gives you string streams. An ostringstream collects everything you send it, then str() hands back the result as a std::string:
ostringstream out;
out << "Order #" << setw(5) << setfill('0') << 42;
string label = out.str(); // "Order #00042"This is the easiest way to turn numbers into nicely formatted strings, for example to show in a window, write to a file or return from a function. Every manipulator that works with cout works here too.
Parsing with istringstream and getline
An istringstream reads from a string the same way cin reads from the keyboard. >> skips spaces and converts text into numbers automatically:
istringstream in("Ana 34 1.68");
string name; int age; double height;
in >> name >> age >> height;To split on another character, such as a comma, use getline(stream, piece, ',') in a loop. C++20 also adds std::format, which formats with placeholders like Python: format("{:.2f}", price). It's in newer compilers, but iomanip works everywhere.
Hexadecimal, octal and scientific notation
Streams can also change the base that whole numbers are printed in. Like fixed, these manipulators are sticky:
cout << hex << 255 << endl; // ff
cout << showbase << 255 << endl; // 0xff
cout << uppercase << 255 << endl; // 0XFF
cout << dec << 255 << endl; // back to 255
cout << noshowbase << nouppercase << oct << 8 << dec << endl; // 10hex is handy for colours, memory addresses and bit patterns. Remember to switch back with dec, or every later integer on that stream will come out in hexadecimal. The same manipulators work for input: in >> hex >> n reads "ff" as 255.
For very large or very small values, scientific prints the number as a mantissa and a power of ten, and setprecision then sets the digits after the decimal point:
cout << scientific << 1234.5 << endl; // 1.234500e+03
cout << setprecision(2) << 1234.5 << endl; // 1.23e+03defaultfloat returns to the normal style, which picks between plain and scientific notation on its own. That's why, with default settings, 1000000.0 prints as 1e+06: it needs seven significant digits, one more than the default six.
C++ Formatting Syntax
Formatting tools
#include <iomanip>
#include <sstream>
cout << fixed << setprecision(2) << x;
cout << setw(10) << left << text;
cout << setfill('0') << setw(5) << n;
cout << boolalpha << flag;
ostringstream out; out << ...; string s = out.str();
istringstream in(line); in >> a >> b;
getline(in, piece, ',');C++ Formatting Summary
#include <iomanip>for manipulators;fixed << setprecision(2)gives two decimal places.setw(n)sets the width of the next value only;left,rightandsetfillare sticky.boolalphaprints true and false as words.ostringstreambuilds formatted strings; callstr()to get the result.istringstreamwith>>orgetline(stream, piece, ',')splits and parses text.
C++ Formatting Examples
Each example shows the code, the output it produces and what each part does.
A neatly aligned receipt
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<string> items = {"Coffee", "Bagel", "Orange juice"};
vector<int> qty = {2, 1, 3};
vector<double> price = {2.80, 3.25, 1.90};
cout << fixed << setprecision(2);
cout << left << setw(14) << "Item" << right << setw(4) << "Qty" << setw(9) << "Total" << endl;
double total = 0;
for (size_t i = 0; i < items.size(); i++) {
double line = qty[i] * price[i];
total += line;
cout << left << setw(14) << items[i] << right << setw(4) << qty[i] << setw(9) << line << endl;
}
cout << left << setw(18) << "TOTAL" << right << setw(9) << total << endl;
return 0;
}Item Qty Total
Coffee 2 5.60
Bagel 1 3.25
Orange juice 3 5.70
TOTAL 14.55Line-by-line explanation
- Line 12Set two decimal places once; it applies to every double printed afterwards.
- Line 13Names are left-aligned in 14 characters, numbers right-aligned in their columns.
- Line 18setw must be repeated before each value, because it only affects the next one.
- Line 20TOTAL fills the width of the first two columns, 14 plus 4.
Building labels with ostringstream
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
using namespace std;
string ticketLabel(int number, double price, bool vip) {
ostringstream out;
out << "TICKET-" << setw(4) << setfill('0') << number
<< " | " << fixed << setprecision(2) << price << " GBP"
<< " | VIP: " << boolalpha << vip;
return out.str();
}
int main() {
cout << ticketLabel(7, 45, false) << endl;
cout << ticketLabel(1203, 120.5, true) << endl;
cout << 3.14159 << endl;
return 0;
}TICKET-0007 | 45.00 GBP | VIP: false
TICKET-1203 | 120.50 GBP | VIP: true
3.14159Line-by-line explanation
- Lines 8 to 11All the formatting happens inside the string stream.
- Line 9setfill('0') pads the number with zeros to 4 digits.
- Line 12str() returns the finished text.
- Line 18cout was never changed, so it still prints numbers in its default style.
Parsing a CSV line
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main() {
string line = "Backpack,Bags,34.99,15";
istringstream in(line);
vector<string> parts;
string piece;
while (getline(in, piece, ',')) {
parts.push_back(piece);
}
string name = parts[0];
double price = stod(parts[2]);
int stock = stoi(parts[3]);
cout << name << " has " << parts.size() << " fields" << endl;
cout << "Stock value: " << price * stock << endl;
istringstream scores("12 7 30 5");
int n, total = 0;
while (scores >> n) total += n;
cout << "Score total: " << total << endl;
return 0;
}Backpack has 4 fields
Stock value: 524.85
Score total: 54Line-by-line explanation
- Lines 12 to 14getline with ',' reads up to each comma, so every field ends up in the vector.
- Lines 17 to 18stod and stoi convert text into a double and an int.
- Lines 22 to 24>> reads one number at a time and stops when the stream runs out.
Common C++ Formatting Mistakes
setprecision without fixed
cout << setprecision(2) << 123.456; // 1.2e+02cout << fixed << setprecision(2) << 123.456; // 123.46Without fixed, the 2 means two significant digits in total.
Expecting setw to stick
cout << setw(8) << "A" << "B" << endl; // only "A" is paddedcout << setw(8) << "A" << setw(8) << "B" << endl;Forgetting the iomanip header
#include <iostream>
cout << setw(5) << 42; // error: setw was not declared#include <iostream>
#include <iomanip>
cout << setw(5) << 42;C++ Formatting in Real Projects
Formatting in real programs
Command-line tools print aligned tables with setw, banking and point-of-sale software formats amounts with fixed and two decimals, and log files use zero-padded times like 09:05:03. String streams are a common way to parse configuration files and CSV data, and to build messages before writing them to a file or sending them over a network.
C++ Formatting FAQ
How do I use std::format in C++20?
Include <format> and write the text with {} placeholders: format("{} scored {:.1f}", name, avg) returns a std::string. Format specs go after the colon, so {:>8.2f} right-aligns a number in 8 characters with 2 decimals and {:05} pads with zeros. It needs a recent compiler, such as g++ 13 with -std=c++20.
How do I reuse a stringstream?
Call ss.str("") to empty its text and ss.clear() to reset any error flags, such as the end-of-input flag left by an earlier read. Forgetting clear() is a common reason a reused istringstream suddenly reads nothing. Often it's simpler to create a fresh stream inside the loop instead.
Can I use printf instead of cout in C++?
Yes. printf from <cstdio> works in C++, and printf("%.2f\n", price) is a familiar style for many programmers. It isn't type-safe, though: a format code that doesn't match the argument's type compiles but prints garbage or worse. Mixing printf and cout in one program is fine unless you've turned off synchronisation with ios::sync_with_stdio(false).
Why is cout slow, and how do I speed it up?
By default, cout is kept in step with C's printf output, and endl flushes the buffer every time. For programs that print a lot, use "\n" instead of endl, and add ios::sync_with_stdio(false); at the start of main. Competitive programmers often add cin.tie(nullptr); as well, which stops cin flushing cout before every read.
What is the difference between cout, cerr and clog?
All three print text, but cout is for normal output, while cerr and clog both write to the standard error stream for diagnostics. cerr is unbuffered, so each message appears immediately even if the program crashes straight afterwards; clog is buffered, which is faster for lots of logging. Sending errors to the error stream lets users redirect normal output to a file and still see the problems.
C++ Formatting Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the code so the value is printed with exactly two decimal places.
cout << << setprecision(2) << 7.5 << endl;
What does this print?
cout << "[" << setw(5) << 42 << "]" << endl;
What does this print?
cout << setfill('*') << setw(6) << left << "ok" << endl;
Which manipulator affects only the next value printed?
How do you split "a;b;c" into pieces in C++?
C++ Formatting Quiz
5 questions to check what you learned.
Which header provides setw and setprecision?
- <iostream>
- <iomanip>
- <string>
- <sstream>
What does
boolalphachange?- Booleans print as true and false instead of 1 and 0
- Letters to capitals
- Sorting order
- Number bases
How do you get the text out of an ostringstream called out?
- out.text()
- string(out)
- out.str()
- out.toString()
What does
stoi("15")return?- "15"
- 1.5
- An error
- The int 15
Why might formatting into an ostringstream be safer than changing cout's settings?
- It's faster
- cout can't format numbers
- cout's sticky settings would otherwise affect every later output in the program
- ostringstream adds colours