C/C++ Arena

Step 3 of 6

Building strings with ostringstream

std::ostringstream is the output twin of istringstream. You write to it with <<, exactly as you would to std::cout, and then take the finished text with .str(). It's the easy way to build a string from numbers and pieces, with all the formatting tools from the last step.

#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

std::string money(long cents) {
    std::ostringstream out;
    out << "
quot; << cents / 100 << "." << std::setw(2) << std::setfill('0') << cents % 100; return out.str(); } std::string bullet_list(const std::vector<std::string>& items) { std::ostringstream out; for (const auto& s : items) out << "- " << s << "\n"; return out.str(); } int main() { std::cout << money(1999) << " " << money(5) << " " << money(120) << "\n"; std::cout << bullet_list({"eggs", "milk"}); }
$19.99 $0.05 $1.20
- eggs
- milk

How it works

Separators: the fencepost problem

Joining values with a separator is a classic off-by-one trap. With 3 values there are only 2 separators, so a naive loop that writes value, sep each time leaves a trailing separator. Two common fixes:

for (size_t i = 0; i < v.size(); i++) {
    if (i > 0) out << sep;     // separator before every item except the first
    out << v[i];
}

or write the first item before the loop and sep, item inside it (after checking the vector isn't empty). Test with an empty vector and a single element: they should give "" and "7".

(C++20 also has std::format, covered later. Streams are still everywhere in existing code.)

Your turn: write std::string join(const std::vector<int>& v, const std::string& sep) that returns the numbers separated by sep, like "1, 2, 3".

Previous: Formatting tables with iomanip Next: Reading files with ifstream