Stream Manipulators and Formatting
Run this and look at the output:
Item Qty Price
Coffee 2 3.5
Espresso 1 2.75
Water 3 1Notice how the columns don’t align properly. The prices are also not formatted consistently, with 1.0 printing out as 1, instead of 1.00.
C++ gives us a set of tools called stream manipulators that control exactly how values appear when printed. Most of them come from the <iomanip> header, so we’ll include it alongside <iostream> in nearly every program that does output formatting:
#include <iostream>#include <iomanip>Let’s fix the output above, one problem at a time.
Problem 1: prices don’t show two decimal places
By default, std::cout prints floating-point numbers with up to six significant digits, dropping trailing zeros. That’s why 1.0 becomes 1 and 3.5 stays 3.5 instead of 3.50.
Two manipulators fix this together. std::fixed tells the stream to always show a decimal point and a consistent number of decimal places. By default that’s six decimal places, but std::setprecision lets you change that number. Here we set it to two:
Item Qty Price
Coffee 2 3.50
Espresso 1 2.75
Water 3 1.00The prices now appear in the desired format. Notice that those manipulators are only set once, on line 5. They keep applying to every number printed after that point, for the rest of the program, unless you explicitly change them. This is called being sticky. Most manipulators work this way.
Problem 2: the columns don’t line up
The real issue is that each value takes up only as much space as it needs. "Coffee" is six characters, "Espresso" is eight, so the rest of the row shifts. To fix this, you need each value to occupy a fixed amount of space regardless of how wide it actually is.
std::setw(n) reserves n characters of width for the next value printed. If the value is shorter, the output is padded with spaces. If the value is wider than n, setw has no effect and the full value prints as-is.
Item Qty Price
Coffee 2 3.50
Espresso 1 2.75
Water 3 1.00But notice that setw is applied repeatedly for each output. That’s because it’s not sticky and resets after each use. Every other manipulator in this lesson is sticky, setw being the only exception.
The reason it works this way is that a persistent width would pad everything you print, including newlines and separators you didn’t intend to pad.
Problem 3: the item names should be left-aligned
Numbers and text can be aligned either way, but convention aligns text labels to the left and numbers to the right. Right now everything is right-aligned, which is the default.
std::left switches to left-alignment. std::right switches back. Both are sticky.
Item Qty Price
Coffee 2 3.50
Espresso 1 2.75
Water 3 1.00Problem 4: adding a divider line
A horizontal line between the header and the rows would make this look like a real table. You could print a string of dashes manually, but there’s an easier way.
std::setfill(c) changes the default padding character (a space) used by setw. You can change that character to '-', print an empty string with a set width, and get a full row of dashes:
std::cout << std::setfill('-') << std::setw(26) << "" << '\n';std::cout << std::setfill(' '); // Reset to spaces immediately afterThe reset to spaces afterward is important. If you forget it, everything you print next will be padded with dashes.
The finished receipt
Here’s the complete version, now with a total row:
Item Qty Price Total
----------------------------------
Coffee 2 3.50 7.00
Espresso 1 2.75 2.75
Water 3 1.00 3.00
----------------------------------
Total 12.75Showing the sign explicitly
On some receipts you might want to show a + or - against each quantity, to distinguish items added from items removed due to an error, for example. By default, C++ only prints the minus sign on negative numbers. std::showpos forces the + sign to appear on positive ones too.
Like the others, it’s sticky, so use std::noshowpos to turn it off.
Saving and restoring formatting state
If something is printing in the wrong format and you can’t figure out why, a sticky manipulator set somewhere earlier is almost always the cause.
A more disciplined approach is to save the formatting state before you change it, and restore it when you’re done: