Formatting Output with Manipulators
The scientific manipulator is sent through the same << operator, but it does not add characters of its own.
Predicting a Line Before Running It
This article follows one small, complete program. Before any explanation, read the code and keep track of what happens at each line. The key question is simple: where does each piece of text go, and when does it reach the screen? The answer to that question explains almost every surprising result you will see with string streams.
- ostringstream oss declares a string stream named oss
- Each << writes a piece into oss; none of them print to the screen
- scientific is a manipulator that changes how the value written after it is formatted
- The final cout line is the only statement that sends text to the screen
What do you think happens?
What does show() print to the screen?
Reveal answer
{temperature, 1.234568e+02}
The text is written into oss first, then scientific is applied, then the number is written in scientific style with the default precision of six digits. The closing brace is written last. Nothing reaches the screen until cout prints oss.str(), followed by a newline.
Tracing the Buffer Line by Line
An ostringstream collects text and values written to it with the << operator, in the order they are written. Think of oss as a single buffer. Every << appends its contents to the end of that buffer, and nothing is removed or reordered. The chain in the example is read from left to right, so the buffer receives its pieces in exactly the order they appear on the line.
Notice that the buffer grows only through text and numbers. The scientific manipulator is sent through the same << operator, but it does not add characters of its own. Its job is to change how the value after it is formatted. The text pieces written before it are not affected by it at all.
Tracing show() statement by statement
Track the contents of oss and the format state after each statement in show(), and say at which point the printed result is determined.
- 1Statement 1: oss << "{temperature, "
The buffer now holds {temperature, . The stream is still in its default format state, so no special notation applies yet.
- 2Statement 2: << scientific
No characters are added to the buffer. The format state of the stream changes so that values written after this point use scientific notation.
- 3Statement 3: << 123.4567890
The number is formatted in scientific style and appended. The buffer now holds {temperature, 1.234568e+02 with no closing brace yet.
- 4Statement 4: << "}"
The closing brace is appended. The buffer is now the complete string {temperature, 1.234568e+02}.
- 5Statement 5: cout << oss.str() << '\n'
oss.str()returns the finished string, cout sends it to the screen, and the newline character ends the line. This is the first moment anything is visible.
The printed line is {temperature, 1.234568e+02}, and it is determined entirely by the order of the << operations before cout runs.
How a Manipulator Changes the Number
A manipulator is a value you send through << to change how the stream formats what comes after it. The scientific manipulator formats numbers in scientific notation. It affects the values written after it in the chain, and only those. Its position in the chain therefore matters: placing scientific before the number changes that number, while placing it after the number would leave the number formatted as it was before.
oss << "{temperature, " << 123.4567890 << "}";Without scientific, the number is written in the stream's default style, which prints 123.457 with six significant digits.
oss << "{temperature, " << scientific << 123.4567890 << "}";With scientific applied before the number, the same value is written as 1.234568e+02.
Reading str() and the cout Line
The str() method returns the string built inside an ostringstream. The statement cout << oss.str() << '\n'; takes that finished string, sends it to cout, and then adds a newline character. The output of cout is therefore the complete string built by the earlier << operations, followed by a line break. Writing to oss does not print anything. Only the cout statement sends text to the screen.
| Feature | cout | ostringstream oss |
|---|---|---|
| Where the text goes | Directly to the screen | Into an in-memory buffer inside the stream |
| When it becomes visible | As soon as it is written | Only after oss.str() is sent to cout |
| Role in the example | Only the final line uses it | Every << in the chain writes into it |
| Effect of a manipulator | Formats values written after it | Formats values written after it before str() is taken |
Comparing the two output destinations
Because the buffer holds everything until str() is called, a line that looks wrong on screen is usually caused by the order of the << chain or by the cout statement that prints oss.str(), not by the text written into oss.
Mistakes That Make the Output Look Wrong
Common mistake Expecting oss << lines to print to the screen
What it looks likeoss << "hello"; with no cout afterward, followed by a check of the terminal.
Why it failsText written into an ostringstream stays in the buffer. Nothing is sent to the screen until cout prints
oss.str().Do this insteadSend the finished string to cout with cout << oss.str() when you want to see it.
Common mistake Placing scientific after the number it should affect
What it looks likeoss << "{temperature, " << 123.4567890 << scientific << "}";Why it failsA manipulator affects only the values written after it in the chain. The number was already written before scientific was applied.
Do this insteadPut scientific before the number, as in << scientific << 123.4567890.
Common mistake Assuming a manipulator adds characters to the output
What it looks likeLooking for the word scientific in the printed line.
Why it failsscientific changes the format of the value that follows it. It does not write any characters of its own.
Do this insteadRead the printed line for the changed number, such as 1.234568e+02, and not for the manipulator name.
Common mistake Reading the chain in the wrong order
What it looks likeAssuming the number is printed before the opening text because the cout line appears last.
Why it failsThe << operator applies in order from left to right, so the pieces enter the buffer in the order they are written.
Do this insteadTrace the chain from left to right, then follow oss.str() into cout.
Common mistake Forgetting the trailing newline when expecting the next output to begin on a new line
Practicing a Trace on a New Chain
Suppose a function writes into an ostringstream named oss with the chain oss << "[" << scientific << 0.5 << "]"; and then prints cout << oss.str() << '\n';. Trace the buffer after each << and state the exact line the program prints. Then say which part of the chain would change if scientific were moved to after 0.5.
Hints
- Start with an empty buffer and append each piece in order from left to right.
- scientific adds no characters; it only changes how 0.5 is written.
- Moving scientific after 0.5 leaves that number in the default style, so compare the default and scientific forms of the same value.
Explain, in one or two sentences, why cout shows nothing until the final line of a function runs, even though several << statements have already executed.
Hints
- Think about where the text is stored between each << and the cout statement.
- The cout statement is the only step that sends text to the screen.
Key Takeaways
- An ostringstream collects text and values written to it with the << operator, in the order they are written, and holds them in an in-memory buffer.
- The
str()method returns the string built inside the ostringstream, and cout <<oss.str()prints that string. - A manipulator such as scientific changes how the values written after it are formatted, so its position in the chain matters and it adds no characters of its own.
- To find a wrong printed line, trace the << chain from left to right and then check the cout statement that outputs
oss.str().