C++ Formatting and String Streams

Control how numbers and text appear with iomanip: decimal places, column widths, alignment and fill characters, then build and parse strings with stringstream.

Lesson 10 of 44Intermediate18 min read

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

C++
#include <iomanip>
double price = 12.5;
cout << fixed << setprecision(2) << price << endl;   // 12.50
  • fixed switches to normal decimal notation, and makes setprecision(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.345 with two decimals shows 2.35 or 2.34 depending on how the binary value is stored, so don't rely on exact halves.

Width, alignment and fill

ManipulatorEffectSticky?
setw(n)The next value takes at least n charactersNo, only the next value
left / rightAlign within the widthYes
setfill('0')Pad with this character instead of spacesYes
boolalphaPrint true/false instead of 1/0Yes

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:

C++
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:

C++
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:

C++
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;   // 10

hex 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:

C++
cout << scientific << 1234.5 << endl;                   // 1.234500e+03
cout << setprecision(2) << 1234.5 << endl;               // 1.23e+03

defaultfloat 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, right and setfill are sticky.
  • boolalpha prints true and false as words.
  • ostringstream builds formatted strings; call str() to get the result.
  • istringstream with >> or getline(stream, piece, ',') splits and parses text.

C++ Formatting Examples

Each example shows the code, the output it produces and what each part does.

Example 1

A neatly aligned receipt

C++
#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;
}
Output
Item           Qty    Total
Coffee           2     5.60
Bagel            1     3.25
Orange juice     3     5.70
TOTAL                 14.55
Line-by-line explanation
  1. Line 12Set two decimal places once; it applies to every double printed afterwards.
  2. Line 13Names are left-aligned in 14 characters, numbers right-aligned in their columns.
  3. Line 18setw must be repeated before each value, because it only affects the next one.
  4. Line 20TOTAL fills the width of the first two columns, 14 plus 4.
Example 2

Building labels with ostringstream

C++
#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;
}
Output
TICKET-0007 | 45.00 GBP | VIP: false
TICKET-1203 | 120.50 GBP | VIP: true
3.14159
Line-by-line explanation
  1. Lines 8 to 11All the formatting happens inside the string stream.
  2. Line 9setfill('0') pads the number with zeros to 4 digits.
  3. Line 12str() returns the finished text.
  4. Line 18cout was never changed, so it still prints numbers in its default style.
Example 3

Parsing a CSV line

C++
#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;
}
Output
Backpack has 4 fields
Stock value: 524.85
Score total: 54
Line-by-line explanation
  1. Lines 12 to 14getline with ',' reads up to each comma, so every field ends up in the vector.
  2. Lines 17 to 18stod and stoi convert text into a double and an int.
  3. Lines 22 to 24>> reads one number at a time and stops when the stream runs out.

Common C++ Formatting Mistakes

setprecision without fixed

Don't
cout << setprecision(2) << 123.456;            // 1.2e+02
Do
cout << fixed << setprecision(2) << 123.456;   // 123.46

Without fixed, the 2 means two significant digits in total.

Expecting setw to stick

Don't
cout << setw(8) << "A" << "B" << endl;         // only "A" is padded
Do
cout << setw(8) << "A" << setw(8) << "B" << endl;

Forgetting the iomanip header

Don't
#include <iostream>
cout << setw(5) << 42;          // error: setw was not declared
Do
#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.

Fill in the blankseasy

Complete the code so the value is printed with exactly two decimal places.

cout <<  << setprecision(2) << 7.5 << endl;
Predict the outputeasy

What does this print?

cout << "[" << setw(5) << 42 << "]" << endl;
Predict the outputmedium

What does this print?

cout << setfill('*') << setw(6) << left << "ok" << endl;
Multiple choicemedium

Which manipulator affects only the next value printed?

Multiple choicehard

How do you split "a;b;c" into pieces in C++?

C++ Formatting Quiz

5 questions to check what you learned.

  1. Which header provides setw and setprecision?

    • <iostream>
    • <iomanip>
    • <string>
    • <sstream>
  2. What does boolalpha change?

    • Booleans print as true and false instead of 1 and 0
    • Letters to capitals
    • Sorting order
    • Number bases
  3. How do you get the text out of an ostringstream called out?

    • out.text()
    • string(out)
    • out.str()
    • out.toString()
  4. What does stoi("15") return?

    • "15"
    • 1.5
    • An error
    • The int 15
  5. 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