C++ / CONSOLE AND FILE INPUT-OUTPUT
Formatting numbers with iomanip controls
Control how C++ streams render numbers: pick fixed or scientific, set digits with setprecision, and align columns with setw and setfill.
What you will learn
- Combine fixed or scientific with setprecision to fix the number of decimals shown
- Build aligned tables with setw, setfill and the left/right adjustment flags
- Predict which manipulators stick and which one (setw) is consumed by one insertion
- Save and restore cout.flags() and cout.precision() so formatting never leaks
Understanding Formatting numbers with iomanip controls
The manipulators in <iomanip> do not format the value sitting next to them in the expression. Each one calls a member function on the stream and mutates flags stored inside the std::cout object itself: std::fixed sets a bit, std::setprecision(2) stores an integer, std::setfill('.') stores a character. Those settings stay in effect for every later insertion, in every function, until something else changes them. This is why a formatting bug in C++ often shows up hundreds of lines away from the manipulator that caused it.
std::setw is the one exception. The field width is reset to zero by every formatted output operation, so it applies to exactly the next item you insert and then disappears. The practical rule that follows: repeat setw before each column of a table, but set fixed, setprecision, setfill and left/right once. Padding uses the fill character on the side chosen by the adjustment flag, and setw never truncates, so a value wider than the field prints in full and quietly shifts the rest of the row.
Precision means two different things depending on the float format field. In the default mode it is the total count of significant digits, trailing zeros are dropped, and the stream may switch to exponent notation on its own when the value does not fit. Once fixed or scientific is set, the same number counts digits after the decimal point and trailing zeros are kept. All of this rounding happens in the output layer only: the double in memory keeps every bit, so 0.1 + 0.2 printed with fixed and precision 2 shows 0.30 even though the stored sum is not exactly 0.3.
<iostream>
<iomanip>
int main() {
double price = 1234.5678;
std::cout << "default: " << price << '\n';
std::cout << std::fixed << std::setprecision(2);
std::cout << "fixed(2): " << price << '\n';
std::cout << "still on: " << price * 2 << '\n';
std::cout << std::setw(12) << price << "|" << price << "|\n";
std::cout << std::setfill('.');
std::cout << std::setw(12) << price << "|\n";
std::cout << std::setw(12) << 7.5 << "|\n";
std::cout << std::setfill(' ') << std::defaultfloat << std::setprecision(6);
std::cout << "restored: " << price << '\n';
}
Every iomanip setting except the field width is sticky state stored inside the stream object, and setprecision counts significant digits until fixed or scientific redefines it to count decimals.
Worked examples
A table that actually lines up
Uses left, right, setw and a fixed precision so the header and three data rows share the same column edges.
<iostream>
<iomanip>
int main() {
const char* name[] = {"bolt", "washer", "hex nut"};
int qty[] = {12, 300, 48};
double unit[] = {0.35, 0.0125, 1.5};
std::cout << std::left << std::setw(10) << "item"
<< std::right << std::setw(6) << "qty"
<< std::setw(10) << "unit" << '\n';
std::cout << std::fixed << std::setprecision(4);
for (int i = 0; i < 3; ++i) {
std::cout << std::left << std::setw(10) << name[i]
<< std::right << std::setw(6) << qty[i]
<< std::setw(10) << unit[i] << '\n';
}
}
Example explained
Line 1setw(10) is written again for every field because the width is consumed by the insertion it precedes.
Line 2std::left stays active until std::right replaces it, so each row sets left for the name and right for the two numbers.
Line 3The header uses the same three widths as the data, which is the only reason its labels sit over their columns.
Line 4fixed with setprecision(4) keeps trailing zeros, so 0.3500 and 1.5000 put their decimal points in the same character position.
What setprecision(3) counts
The same precision value produces three very different renderings depending on the float format flag in effect.
<iostream>
<iomanip>
int main() {
double v = 0.000123456789;
std::cout << std::setprecision(3);
std::cout << "default: " << v << '\n';
std::cout << "fixed: " << std::fixed << v << '\n';
std::cout << "scientific: " << std::scientific << v << '\n';
std::cout << std::defaultfloat << std::setprecision(6);
std::cout << "42 as double: " << 42.0 << '\n';
std::cout << std::showpoint << "with showpoint: " << 42.0 << '\n';
}
Example explained
Line 1In the default format, 3 means three significant digits, so the value keeps its magnitude and prints 0.000123.
Line 2std::fixed reinterprets the same 3 as three digits after the point, which discards the whole value and prints 0.000.
Line 3std::scientific replaces fixed instead of combining with it because both live in one bitfield, and the exponent is padded to two digits.
Line 4std::showpoint forces the default format to keep trailing zeros, so 42.0 prints as 42.0000 with six significant digits instead of 42.
Putting the stream back the way you found it
A helper changes format state, then restores the saved flags and precision so the caller's output is unaffected.
<iostream>
<iomanip>
void printTemp(double t) {
std::ios_base::fmtflags saved = std::cout.flags();
std::streamsize savedPrec = std::cout.precision();
std::cout << std::fixed << std::setprecision(1) << t << " C\n";
std::cout.flags(saved);
std::cout.precision(savedPrec);
}
int main() {
double x = 3.14159265;
std::cout << x << '\n';
printTemp(21.5);
std::cout << x << '\n';
}
Example explained
Line 1cout.flags() returns all format bits at once, so one assignment later undoes fixed, left, showpoint and the rest together.
Line 2precision() is stored separately from the flags and needs its own save and restore.
Line 3Without those two restores the last line would print 3.1, and nothing in main would hint that printTemp was responsible.
Line 4The manipulators inside the helper affect std::cout, not the argument t, which is why the fix belongs to the stream and not the value.
Important notes
setw pads but never truncates, so a nine-character value in a setw(6) field prints in full and pushes everything after it out of alignment.
Setting fixed and scientific at the same time is not 'both' - in C++11 that bit combination means hexfloat; and digit grouping such as 1,234,567 comes from imbuing a locale, not from anything in <iomanip>.
Common mistakes
Writing std::cout << std::setw(8) << a << b and expecting two padded columns: the width is consumed by a, so b prints flush against it and the table collapses.
Calling setprecision(2) without fixed and expecting two decimals: 1234.5678 prints as 1.2e+03, because in the default format precision is a significant-digit budget and the stream switches to exponent form when the value does not fit.
Setting fixed in one function and never undoing it: a later std::cout << 1e-9 prints 0.000000 instead of 1e-09, with nothing at the failure site pointing back to the cause.
Try it yourself
Change, predict, then run
Print a miles-to-kilometres table for 1, 5, 10 and 26.2 miles, with the miles value fixed to 1 decimal in a setw(8) field and the kilometres value fixed to 3 decimals in a setw(10) field. Then restore cout to its default format and print 26.2 again to confirm the reset worked.
Open the C++ workspaceCheck your understanding
With no earlier formatting calls, what does std::cout << std::setprecision(3) << 1234.5678 print?
- 1234.57
- 1234.568
- 1.23e+03
- 1234
Show answer
No float format flag has been set, so the stream is in its default mode where precision is a total significant-digit budget. Three significant digits cannot represent a four-digit integer part in positional notation, so the stream falls back to exponent form. 1234.568 is tempting but that is what you get only after std::fixed makes precision mean decimals, and 1234.57 is the untouched default precision of 6.