17.5.1. Formatted Input and Output

In addition to its condition state (§ 8.1.2, p. 312), each iostream object also maintains a format state that controls the details of how IO is formatted. The format state controls aspects of formatting such as the notational base for integral values, the precision of floating-point values, the width of an output element, and so on.

The library defines a set of manipulators1.2, p. 7), listed in Tables 17.17 (p. 757) and 17.18 (p. 760), that modify the format state of a stream. A manipulator is a function or object that affects the state of a stream and can be used as an operand to an input or output operator. Like the input and output operators, a manipulator returns the stream object to which it is applied, so we can combine manipulators and data in a single statement.

Our programs have already used one manipulator, endl, which we “write” to an output stream as if it were a value. But endl isn’t an ordinary value; instead, it performs an operation: It writes a newline and flushes the buffer.

Many Manipulators Change the Format State

Manipulators are used for two broad categories of output control: controlling the presentation of numeric values and controlling the amount and placement of padding. Most of the manipulators that change the format state provide set/unset pairs; one manipulator sets the format state to a new value and the other unsets it, restoring the normal default formatting.


Image Warning

Manipulators that change the format state of the stream usually leave the format state changed for all subsequent IO.


The fact that a manipulator makes a persistent change to the format state can be useful when we have a set of IO operations that want to use the same formatting. Indeed, some programs take advantage of this aspect of manipulators to reset the behavior of one or more formatting rules for all its input or output. In such cases, the fact that a manipulator changes the stream is a desirable property.

However, many programs (and, more importantly, programmers) expect the state of the stream to match the normal library defaults. In these cases, leaving the state of the stream in a nonstandard state can lead to errors. As a result, it is usually best to undo whatever state changes are made as soon as those changes are no longer needed.

Controlling the Format of Boolean Values

One example of a manipulator that changes the formatting state of its object is the boolalpha manipulator. By default, bool values print as 1 or 0. A true value is written as the integer 1 and a false value as 0. We can override this formatting by applying the boolalpha manipulator to the stream:

cout << "default bool values: " << true << " " << false
     << " alpha bool values: " << boolalpha
     << true << " " << false << endl;

When executed, this program generates the following:

default bool values: 1 0
alpha bool values: true false

Once we “write” boolalpha on cout, we’ve changed how cout will print bool values from this point on. Subsequent operations that print bools will print them as either true or false.

To undo the format state change to cout, we apply noboolalpha:

bool bool_val = get_status();
cout << boolalpha    // sets the internal state of cout
     << bool_val
     << noboolalpha; // resets the internal state to default formatting

Here we change the format of bool values only to print the value of bool_val. Once that value is printed, we immediately reset the stream back to its initial state.

Specifying the Base for Integral Values

By default, integral values are written and read in decimal notation. We can change the notational base to octal or hexadecimal or back to decimal by using the manipulators hex, oct, and dec:

cout << "default: " << 20 << " " << 1024 << endl;
cout << "octal: " << oct << 20 << " " << 1024 << endl;
cout << "hex: " << hex << 20 << " " << 1024 << endl;
cout << "decimal: " << dec << 20 << " " << 1024 << endl;

When compiled and executed, this program generates the following output:

default: 20 1024
octal: 24 2000
hex: 14 400
decimal: 20 1024

Notice that like boolalpha, these manipulators change the format state. They affect the immediately following output and all subsequent integral output until the format is reset by invoking another manipulator.


Image Note

The hex, oct, and dec manipulators affect only integral operands; the representation of floating-point values is unaffected.


Indicating Base on the Output

By default, when we print numbers, there is no visual cue as to what notational base was used. Is 20, for example, really 20, or an octal representation of 16? When we print numbers in decimal mode, the number is printed as we expect. If we need to print octal or hexadecimal values, it is likely that we should also use the showbase manipulator. The showbase manipulator causes the output stream to use the same conventions as used for specifying the base of an integral constant:

• A leading 0x indicates hexadecimal.

• A leading 0 indicates octal.

• The absence of either indicates decimal.

Here we’ve revised the previous program to use showbase:

cout << showbase;    // show the base when printing integral values
cout << "default: " << 20 << " " << 1024 << endl;
cout << "in octal: " << oct  << 20 << " " << 1024 << endl;
cout << "in hex: " << hex  << 20 << " " << 1024 << endl;
cout << "in decimal: " << dec << 20 << " " << 1024 << endl;
cout << noshowbase;  // reset the state of the stream

The revised output makes it clear what the underlying value really is:

default: 20 1024
in octal: 024 02000
in hex: 0x14 0x400
in decimal: 20 1024

The noshowbase manipulator resets cout so that it no longer displays the notational base of integral values.

By default, hexadecimal values are printed in lowercase with a lowercase x. We can display the X and the hex digits af as uppercase by applying the uppercase manipulator:

cout << uppercase << showbase << hex
     << "printed in hexadecimal: " << 20 << " " << 1024
     << nouppercase << noshowbase << dec << endl;

This statement generates the following output:

printed in hexadecimal: 0X14 0X400

We apply the nouppercase, noshowbase, and dec manipulators to return the stream to its original state.

Controlling the Format of Floating-Point Values

We can control three aspects of floating-point output:

• How many digits of precision are printed

• Whether the number is printed in hexadecimal, fixed decimal, or scientific notation

• Whether a decimal point is printed for floating-point values that are whole numbers

By default, floating-point values are printed using six digits of precision; the decimal point is omitted if the value has no fractional part; and they are printed in either fixed decimal or scientific notation depending on the value of the number. The library chooses a format that enhances readability of the number. Very large and very small values are printed using scientific notation. Other values are printed in fixed decimal.

Specifying How Much Precision to Print

By default, precision controls the total number of digits that are printed. When printed, floating-point values are rounded, not truncated, to the current precision. Thus, if the current precision is four, then 3.14159 becomes 3.142; if the precision is three, then it is printed as 3.14.

We can change the precision by calling the precision member of an IO object or by using the setprecision manipulator. The precision member is overloaded (§ 6.4, p. 230). One version takes an int value and sets the precision to that new value. It returns the previous precision value. The other version takes no arguments and returns the current precision value. The setprecision manipulator takes an argument, which it uses to set the precision.


Image Note

The setprecision manipulators and other manipulators that take arguments are defined in the iomanip header.


The following program illustrates the different ways we can control the precision used to print floating-point values:

// cout.precision reports the current precision value
cout  << "Precision: " << cout.precision()
      << ", Value: "   << sqrt(2.0) << endl;
// cout.precision(12) asks that 12 digits of precision be printed
cout.precision(12);
cout << "Precision: " << cout.precision()
     << ", Value: "   << sqrt(2.0) << endl;
// alternative way to set precision using the setprecision manipulator
cout << setprecision(3);
cout << "Precision: " << cout.precision()
     << ", Value: "   << sqrt(2.0) << endl;

When compiled and executed, the program generates the following output:

Precision: 6, Value: 1.41421
Precision: 12, Value: 1.41421356237
Precision: 3, Value: 1.41

Table 17.17. Manipulators Defined in iostream

Image

This program calls the library sqrt function, which is found in the cmath header. The sqrt function is overloaded and can be called on either a float, double, or long double argument. It returns the square root of its argument.

Specifying the Notation of Floating-Point Numbers

Image Best Practices

Unless you need to control the presentation of a floating-point number (e.g., to print data in columns or to print data that represents money or a percentage), it is usually best to let the library choose the notation.


We can force a stream to use scientific, fixed, or hexadecimal notation by using the appropriate manipulator. The scientific manipulator changes the stream to use scientific notation. The fixed manipulator changes the stream to use fixed decimal.

Image

Under the new library, we can also force floating-point values to use hexadecimal format by using hexfloat. The new library provides another manipulator, named defaultfloat. This manipulator returns the stream to its default state in which it chooses a notation based on the value being printed.

These manipulators also change the default meaning of the precision for the stream. After executing scientific, fixed, or hexfloat, the precision value controls the number of digits after the decimal point. By default, precision specifies the total number of digits—both before and after the decimal point. Using fixed or scientific lets us print numbers lined up in columns, with the decimal point in a fixed position relative to the fractional part being printed:

cout << "default format: " << 100 * sqrt(2.0) << ' '
     << "scientific: " << scientific << 100 * sqrt(2.0) << ' '
     << "fixed decimal: " << fixed << 100 * sqrt(2.0) << ' '
     << "hexadecimal: " << hexfloat << 100 * sqrt(2.0) << ' '
     << "use defaults: " << defaultfloat << 100 * sqrt(2.0)
     << " ";

produces the following output:

default format: 141.421
scientific: 1.414214e+002
fixed decimal: 141.421356
hexadecimal: 0x1.1ad7bcp+7
use defaults: 141.421

By default, the hexadecimal digits and the e used in scientific notation are printed in lowercase. We can use the uppercase manipulator to show those values in uppercase.

Printing the Decimal Point

By default, when the fractional part of a floating-point value is 0, the decimal point is not displayed. The showpoint manipulator forces the decimal point to be printed:

cout << 10.0 << endl;         // prints 10
cout << showpoint << 10.0     // prints 10.0000
     << noshowpoint << endl;  // revert to default format for the decimal point

The noshowpoint manipulator reinstates the default behavior. The next output expression will have the default behavior, which is to suppress the decimal point if the floating-point value has a 0 fractional part.

Padding the Output

When we print data in columns, we often need fairly fine control over how the data are formatted. The library provides several manipulators to help us accomplish the control we might need:

setw to specify the minimum space for the next numeric or string value.

left to left-justify the output.

right to right-justify the output. Output is right-justified by default.

internal controls placement of the sign on negative values. internal left-justifies the sign and right-justifies the value, padding any intervening space with blanks.

setfill lets us specify an alternative character to use to pad the output. By default, the value is a space.


Image Note

setw, like endl, does not change the internal state of the output stream. It determines the size of only the next output.


The following program illustrates these manipulators:

int i = -16;
double d = 3.14159;
// pad the first column to use a minimum of 12 positions in the output
cout << "i: " << setw(12) << i << "next col" << ' '
     << "d: " << setw(12) << d << "next col" << ' ';
// pad the first column and left-justify all columns
cout << left
     << "i: " << setw(12) << i << "next col" << ' '
     << "d: " << setw(12) << d << "next col" << ' '
     << right;                // restore normal justification
// pad the first column and right-justify all columns
cout << right
     << "i: " << setw(12) << i << "next col" << ' '
     << "d: " << setw(12) << d << "next col" << ' ';
// pad the first column but put the padding internal to the field
cout << internal
     << "i: " << setw(12) << i << "next col" << ' '
     << "d: " << setw(12) << d << "next col" << ' ';
// pad the first column, using # as the pad character
cout << setfill('#')
     << "i: " << setw(12) << i << "next col" << ' '
     << "d: " << setw(12) << d << "next col" << ' '
     << setfill(' '),   // restore the normal pad character

When executed, this program generates

i:          -16next col
d:      3.14159next col
i: -16         next col
d: 3.14159     next col
i:          -16next col
d:      3.14159next col
i: -         16next col
d:      3.14159next col
i: -#########16next col
d: #####3.14159next col

Table 17.18. Manipulators Defined in iomanip

Image
Controlling Input Formatting

By default, the input operators ignore whitespace (blank, tab, newline, formfeed, and carriage return). The following loop

char ch;
while (cin >> ch)
    cout << ch;

given the input sequence

a b    c
d

executes four times to read the characters a through d, skipping the intervening blanks, possible tabs, and newline characters. The output from this program is

abcd

The noskipws manipulator causes the input operator to read, rather than skip, whitespace. To return to the default behavior, we apply the skipws manipulator:

cin >> noskipws;  // set cin so that it reads whitespace
while (cin >> ch)
    cout << ch;
cin >> skipws;    // reset cin to the default state so that it discards whitespace

Given the same input as before, this loop makes seven iterations, reading whitespace as well as the characters in the input. This loop generates

a b    c
d


Exercises Section 17.5.1

Exercise 17.34: Write a program that illustrates the use of each manipulator in Tables 17.17 (p. 757) and 17.18.

Exercise 17.35: Write a version of the program from page 758, that printed the square root of 2 but this time print hexadecimal digits in uppercase.

Exercise 17.36: Modify the program from the previous exercise to print the various floating-point values so that they line up in a column.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.106.233