27 Formatted Input-Output Operations in C++

Jyoti Pareek

Introduction

 

This module introduces the techniques to perform formatted input/output operations from standard devices using member functions of stream classes and using manipulators. In previous module, we learnt text I/O using operators (insertion, extraction)and member functions (put, get, getline) without specifying format. When format is not specified, it uses default values for formatting. Formatting is the process of transforming a byte sequence into a human-readable character sequence. The objective of this module is to learn formatting dataas per need of the users. We will also study details about errors in input/output operations.

  1. Formatting

Internal representation of numeric data is in binary; need not be in human readable form. Text I/O involves formatting or converting the data into the external representation as a sequence of characters.

 

For example, a value 00000000 01000001 is read from memory as short int. When this number is written to output stream, it is transformed into characters ‘6’ and ‘5’ and stored in the stream. In the same way, when reading a number from keyboard, if user have entered integer number using keys ‘6’ and ‘5’, these two characters are read from input stream and are converted to the binary representation of a number 65 for storage in the program.

 

Simple input and output of items using extraction and insertion operators is notsufficient in many cases. For example, in case of tabular output of student’s result statement; names should be left aligned, marks should be right aligned, decimal point should be aligned in percentage of marks and the columns should be of specific width and so on. Iostreams allow controllingsuch formatting features inmany ways with the help of formatting flags.

With iostreams, one can specify:

  • The width of the field and the adjustment of the outputwithin this field;
  • The decimal point to be aligned;
  • The precision and format of floating point numbers;
  • Whether to skip white spaces when reading from aninput stream;
  • Whether integral values are displayed in decimal, octal or hexadecimal format;
  • … many more

1.1.    Formatting Flags

 

Formatting control is possible via a stream’s format state. Associated with each stream, there are a number of format state variables that control the details of formatting. These variables are defined in ios class. Three format state variables are used to store the values of width, precision and fill character. In additional to these variables, an enum variable is used for formatting flags. Formatting flags are represented by one or more bits in a data member of type fmtflags in class ios_base. It is defined as enumerated data type. The bits act as on/off switches that specify various formats as shown below.

Format Group Default i/o Effect
flag
left adjustfield right o Left-align, padding with fill character on right
right Right-align, padding with fill character on left
internal padding between sign or base indicator and number [-
12.34]
dec basefield dec i,o integer to decimal form
oct integer to octal form
hex integer to hexadecimal form
fixed floatfield fixed o Floating point in fixed point notation [123.45]
scientific Floating point in scientific notation [1.2345E2]
skipws 1 i When unset to 0, white spaces are not ignored
boolalpha 0 i,o When set to 1, bool values converted to string “true” or
“false”
showpos 0 o When set, show + sign before non-negative integers
showpoint 0 o Always show decimal point in floating point o/p [123.00]
showbase 0 o Show base indicator (0 for octal, 0x for hex)
uppercase 0 o Use uppercase X, E, and hex output letters (ABCDEF)
unitbuf 0 o Flush o/p stream after each formatting operation

The bits of formatting flag and the values of format state variables can be set/reset or get using member functions of ios class and also by using manipulators.

  1. Formatting using ios functions

The ios class contains a number of functions that can be used to set/unset the formatting flags and perform other tasks using format state variables.

Function Default Effect
width() 0 Minimum field with to be used
precision() 6 Precision for number of digits after decimal point
fill() Space character Fill character to be used for padding
setf() 0 Set bit of format flag
unsetf() 0 Reset bit of format flag

First three functions can be used to set the value of the format state variables with specified argument and they all return the old the value of the corresponding variable. For example, w=width(5); sets the value of format state variable width to 5 and returns its old value.These functions can also be used without specifying argument. In this case, it simply returns the value of the format state variables. Ex. w=width(); returns the value of width.Functions setf() and unsetf() takes bits of format flags as arguments and set/unset corresponding bits.

 

The effect of setting a format parameter (format state variables and format flag) is usually permanent. Thus, the parameter setting is in effect until the setting is explicitly changed. The only exception to this rule is the field width. The width is automatically reset to its default value 0 after each input or output operation that uses the field width..

2.1.    Function width():

 

Function width() is used to get/set width variable. Width specifies number of characters or positions to be used during input/output. Even though it can be used during input, it is more meaningful to use it for output purpose.

 

Syntax: int ios::width (int num=0)

  • ·      Sets the field width to num
  • ·      Returns the previous value of width parameter.
  • ·      Default is 0, which means to use as many characters as necessary.
  • ·      Thewidth setting is not permanent. The value of the width format variableis reset to zero (the default) after its use.
  • ·      For output, num is the minimum width to be used.

o   If the specified width is less than the required width, width specification is ignored. Output is not truncated. Output is written using as many characters as needed.

  •   If the specified width is larger than required, extra positions are padded with fill character. Default fill character is space.
  •    For input, num is the maximum width to be used.
  •   While extracting number or string, if invalid character or white space appears before num characters, extraction is terminated ignoring specified width.

For example:

 

int i=1234; char* str[10]=”Hello”;

cout.width(7);

cout<<i << str;

 

In the above example, value of the first item i will be displayed using a width of 7 positions and the width parameter will be reset to its default value 0. Now, value of str will be displayed using minimum width 0; i.e 5 positions as necessary. When used with extraction operator, width is maximum to be used. For example,

cin.width(7); cin >> i;

cin.width(7); cin>> str;

Let the input be: 1234GujaratHello

 

Here, extraction for integer i is independent of width parameter. Characters 1234 are extracted and transformed to binary number to be stored in variable i. Next, 7 characters will be extracted and stored in variable str. Thus specified width will be applied first time to item str and reset to 0.

 

Remember the following:

  •    All format parameter variables are different for different streams. Thus, different width variables for cin and cout streams.
  •     Width parameter is reset after its use.
  •   Specified width is the minimum to be used for ostream. If the item requires more width, output will be written using as many characters as required; ignoring the specified width.
  • ·  With istream, width is the maximum to be used. Extraction stops at white space or any invalid character.

 

2.2.    Function fill():

 

Function fill() is used to get/set fill character used as padding character to fill extra positions.Syntax: char ios::fill (char padding = ‘ ’)

  • Set the padding character to be used to fill extra positions
  • Default: blank; a space character
  • Permanent setting, remain in effect until changed

For example:

cout.width(7);

cout.fill (‘*’);

cout << 1234;

cout.width(7);

cout << “Hello”;

 

Output will be: ***1234**Hello

 

Note that unlike width, the value of fill format variable is retained.

 

2.3.    Function precision():

 

This function is used to specify number of significant digits in case of floating point numbers. It also returns the old value of precision.

 

Syntax: int ios::precision (int num = 6)

  • Set the number of significant digits to num for input and output of floating point numbers
  • Default precision is of 6 significant digits
  • Remains in effect until changed
  • When specified precision is shorter than required
  • o Performs rounding of digits after decimal point
  • o If not enough to accommodate integral part, it uses scientific format

 

For example:

 

cout.fill (‘*’);

cout.precision(7);

cout.width(10);

cout << 1234.567<< endl;

cout.precision(8);

cout.width(10);

cout << 1234.567<< endl;

cout.precision(5);

cout.width(10);

cout << 1234.567<< endl;

cout.precision(3);

cout.width(10);

cout << 1234.567<< endl;

 

Output is:

 

**1234.567

**1234.567

****1234.6

*1.23e+003

 

With precision 7 and 8, result remains same as the number have only seven significant digits.Note the output of number 1234.567 with precision 5 and 3.

  • With precision 5, there is no problem to accommodate integral part 1234. Digits in fractional part are rounded as only 5 significant digits are specified for output.
  • With precision 3, there is a problem to accommodate even integral part 1234. So a number is transformed into scientific format and written using e notation.

 

Now try the following code.

 

cout.set(ios::fixed);

cout.precision(2);

cout.width(10);

cout << 1234.567 << endl;

 

The result is ***1234.57. Here, the precision is 2; shorter than required. But, format flag is set to fixed point notation. Due to this, a number is formatted using fixed point notation instead of scientific notation. Also note that it has considered precision 2 as two significant digits after decimal point in fixed point notation.

 

2.4.    Function setf():

 

Format flags (bits of format flag variable) can be set using setf() function in two forms as follows.

 

Syntax:

fmtflags ios::setf (fmtflags flg)

fmtflags ios::setf (fmtflags flg, fmtflags mask)

  • Sets format flags as specified in first argument
  • Returns old value of format flags
  • To specify format flags, precede flag name with the class name ios and the scope-resolution operator (for example, ios::fixed)
  • To set multiple flags, use OR (|) operator to combine them (for example, ios::fixed | ios_base::uppercase )
  • Two-argument version of setf()
  • o Some format flags are grouped, because they are mutually exclusive. For example, the adjustment of the output within an output fieldcan be either left or right or internal. One and only one of these three format flags can be set at a time. To set one of these bits to 1, it requires other two to reset to 0. To make this easier, a two-argument version of setf() can be used. It first resets all the bits of the group fieldspecified in second argument and then set the necessary bit as specified in first argument. This makes it easier to reset the relevant flags before setting a new one. For example, cout.setf(ios::left, ios::adjustfield); clears all the flags dealing with text justification and then sets the left flag for left-justified output.

 

First argument: Flag to set Second argument: group to reset all its flags
left, right, internal Adjustfield
dec, oct, hex Basefield
scientific, fixed Floatfield

 

2.5.    Function unsetf():

 

Format flags can be reset using unsetf() function.

 

Syntax:fmtflags ios::unsetf (fmtflags flg)

  • Reset flags as specified in argument
  • Returns the old values oftheflags

2.6.    Function flag():

 

A complete collection of flags (bits) can be set or get using flag() function. There are two forms of flag() function; with and without parameter.

 

Syntax:fmtflags ios::flags ()

fmtflags ios::flags (fmtflags value)

  • Call to flag() without argument returns the current value of the complete collection of flags. For example, int flg = flags();
  • Call to flag() with argument sets entire collection of flags with a specified argument

Note: Use ios::setf() or ios::unsetf() to change one format flag (bit) at a time.

  1. Formatting using manipulators

Like member functions of ios class, manipulators are also used to perform the task of formatting input/output. Manipulators are special type of non-member functionsthat can be included in an insertion or extraction chain.

 

The formatting member functions explained above return the format control parameters like width, precision, fill character and format flag. Because they do not return a reference to a stream, they cannot be cascaded with insertion (<<) or extraction (>>) operator. Being member functions of ios class, they require objects of stream class to invoke them.

 

Manipulators are non-member functions returning a reference to a stream. So they can be used with shift operator in cascaded fashion. Manipulators are non-member functions, so they do not require to be called using dot operator with stream objects. In many examples, we have used manipulator endl with << operatorto have newline or to insert line break.

 

Following table lists the manipulators equivalent to ios functions.

 

Manipulator Equivalent ios member function
setw() width()
setprecision() precision()
setfill() fill()
setiosflags() setf()
resetiosflags() unsetf()

 

To use manipulators, it requires to include <iomanip> in C++ program.

 

Following code is written using ios function members. See how it can be written in a single statement using manipulators.

cout<<“Numbers left justified in width 10 : ” << endl;

cout.setf(ios_base::left,ios_base::adjustfield);

cout.width(10);

cout<<12;

cout.width(10);

cout<<123<< ‘\n’;

The above C++ statements can be written in a single statement using manipulators as follows:

cout<< “Numbers left justified in width 10 : ” << endl << left << setw(10) << 12 << setw(10) << 123 << ‘\n’ ;

Note the following:

 

·      Use of manipulator name‘left’ instead of manipulator call setiosflags(ios::left) which is equivalent to cout.setf(ios_base::left,ios_base::adjustfield);

·      Use of setw(10) instead of cout.width(10);

·      Use of manipulators cascaded with << operator

 

Thus manipulators can be considered as non-member operator overloaded functions with shift operators and returning a reference to a stream. Hence a manipulatorcan be extracted from or inserted into a stream together with otherobjects that have the shift operators defined. Users can also define their own manipulators. (Explained later)

 

3.1.    Shorthand manipulators:

 

Shorthand manipulators are the short names that can be used to set/reset ios format flags as a replacement to calling function setiosflags() or resetiosflags(). Some such manipulators are provided in pairs to have toggle effect.

 

Manipulator i/o Effect equivalent to
left o Left-align, padding with fill character ios::setf(ios::left) or
on right setiosflags(ios::left)
right Right-align, padding with fill character ios::setf(ios::right) or
on left setiosflags(ios::right)
internal padding between sign or base indicator ios::setf(ios::internal) or
and number [-  12.34] setiosflags(ios::internal)
dec i,o integer to decimal form ios::setf(ios::dec) or
setiosflags(ios::dec)
oct integer to octal form ios::setf(ios::oct) or
setiosflags(ios::oct)
hex integer to hexadecimal form ios::setf(ios::hex) or
setiosflags(ios::hex)
fixed o Floating point in fixed point notation ios::setf(ios::fixed) or
[123.45] setiosflags(ios::fixed)
scientific Floating point in scientific notation ios::setf(ios::scientific) or
[1.2345E2] setiosflags(ios:: scientific)
skipws i Skips leading white spaces ios::setf(ios::skipws) or
setiosflags(ios:: skipws)
noskipws i Do not skip leading white spaces ios::unsetf(ios::skipws) or
resetiosflags(ios:: skipws)
boolalpha i,o bool values converted to string “true” or ios::setf(ios::boolalpha) or
“false” setiosflags(ios:: boolalpha)
noboolalpha i,o bool values not converted to string ios::unsetf(ios::boolalpha) or
“true” or “false” resetiosflags(ios:: boolalpha)
showpos o Generate + sign before non-negative ios::setf(ios::showpos) or
numbers setiosflags(ios:: showpos)
nohowpos o Do not generate + sign before non- ios::unsetf(ios::showpos) or
negative numbers resetiosflags(ios:: showpos)
showpoint o Always generate a decimal point in ios::setf(ios::showpoint) or
floating point o/p [123.00] setiosflags(ios:: showpoint)
noshowpoint o Do not generate a decimal point in ios::unsetf(ios::showpoint) or
floating point o/p [123] resetiosflags(ios:: showpoint)
showbase o Generate prefix indicating base of an ios::setf(ios::showbase) or
integer (0 for octal, 0x for hex) setiosflags(ios:: showbase)
noshowbase o Do not generate base indicator for an ios::unsetf(ios::showbase) or
integer resetiosflags(ios:: showbase)
uppercase o Use uppercase X, E, and hex output ios::setf(ios::uppercase) or
letters (ABCDEF) setiosflags(ios:: uppercase)
nouppercase o Use lowercase x, e, and hex output ios::unsetf(ios::uppercase) or
letters (abcdef) resetiosflags(ios:: uppercase)
unitbuf o Flush o/p stream after each formatting ios::setf(ios::unitbuf) or
operation setiosflags(ios:: unitbuf)
nounitbuf o Do not flush o/p stream after each ios::unsetf(ios::unitbuf) or
formatting operation resetiosflags(ios:: unitbuf)
ws i Skip any white space stored in stream.
ends o Inserts end of string character
endl o Inserts new line character and flushes
output buffer
flush o Flushes output buffer flush()

 

3.2.    User-defined manipulators

 

User can define manipulators as per need. For example, define manipulator km to print KiloMeter, define manipulator prhead to print header in a report, define manipulator dash to print dash line etc.The code structure for user-defined manipulator is as follows:

 

ostream &<manipulator_name> (ostream &<parameter_name)

{

  • // code for formatting … return <parameter_name>;}

In the above structure, use istream& in place of ostream& for defining input manipulator.For example, define manipulator km to print KiloMeter as follows:

ostream& km (ostream & pout) { pout << “ KiloMeter” ; return pout;}

Using cout << 200 << km; will output 200 KiloMeter

Another example, define manipulator to print dashline as follows:

ostream & dash (ostream & pout)

{

pout << setw(80) << left << setfill(‘-‘) << ” ” << endl;

pout << setfill(‘ ‘);   reset back to space character

return pout;

}

 

Now using cout << dash; will print a line with 80 dash (-) characters.

 

Consider one more example. Suppose the numbers are to be formatted to be in fixed point notation with a precision of two significant digits after decimal point and to be aligned on right, then it requires three format settings to be used as

 

cout << setprecision(2) << fixed << right;

User can define manipulator named fixed2 as follows to perform above task:

ostream & fixed2 (ostream & pout)

{

pout <<setprecision(2) << fixed << right;

return pout;

}

 

Using cout << setw(8) << fixed2 << 123.456; will print  123.46 using fixed2 manipulator.

 

3.3.    Difference between formatting using ios function and manipulator:Using ios functions

     Functions are members of ios class  Require only <iostream> file to be included  Return the previous status of format parameters like width, precision, fill character and format flags  Used as a standalone statement, ex. cout.width(10); cout.fill(‘*’); For some manipulators, there is no equivalent function available, for example, endl   No shorthand names to use  Not possible to define user-defined member functions in ios class, one may create another class inheriting from ios and add user-defined functions  Function calls always requires use of (), example:

int w = width();

Need to use setf() and unsetf() with same format flag to have toggle effect

 

4.  The State of Streams

 

Using manipulatorsManipulators are non-member functions Require <iomanip> file to be included additionally Does not return previous status of format parameters, Return a reference to stream Can be cascaded with shift operator, ex. cout << setw(10) << setfill(‘*’);  Manipulators available corresponding to all ios functions Can use shorthand names User-defines manipulators can be easily created  Manipulators without argument can be called without (), example: left, hex, endl Paired manipulators with toggle effect, Ex.boolalpha, noboolalphaEach stream has an error state that identifies whether an I/O operation was successful or not. If unsuccessful, it shows thereason for the failure. The state of a stream is determined by the settings of a number of flags. These error-status flagsare enum member constants of type iostate defined in the base class ios_base.

 

Error-Status Flags are as follows:
Name of the flag Meaning
goodbit No errors, not flags set, value 0
eofbit Encountered end of file while input
Error due to an attempt to read past end of
input sequence
failbit Operation failed, may be user error or
premature EOF, but the stream is ok.
Example: An input failed to read expected
character ( a number is to be read, but next
character is a letter) , or an output failed to
generate desired character
badbit If stream has somehow become corrupted or
data is lost

 

Flag eofbit is set when it is attempted to read past end of input sequence. Consider following two cases:

 

1.      Assume extraction of characters from input stream. Remember that when the lastcharacter is read, the stream is still in good state; eofbit is not yetset. Any subsequent extraction, however, will be an attempt toread past the end of the input sequence. Thus, eofbit will be set.

 

2.     Assume extraction of an integer or astring.Here, the input operators read characters until they find a separator, or hit the end of the input sequence. If the input contains the sequence 912749<eof> and an integer is extracted, eofbit will be set.Flag failbit is set as the result of a read (or write)operation that fails. For example, when extracting an integer, ifthe input sequence contains only white spaces, then the extractionof an integer will fail and the failbit will be set. Let us consider above two cases:

 

1.     Assume extraction of characters from input stream. After reading the last available character, the extraction not onlyreads past the end of the input sequence; it also fails to extractthe requested character. Hence, both failbit and eofbit are set.

 

2.     Assume extraction of integers from input stream containing 912749<eof>. Here, although the end of the input sequence willbe reached by extracting the integer, the input operation doesnot fail. The desired integer will indeed be read. Hence, in thissituation, only the eofbit will be set.There are othersituations that can trigger failure. For example, file streams setfailbit if the associated file cannot be opened.

 

Flag badbit indicates problems with the underlyingstream buffer. There might be memory shortage while creating stream buffer itself, or code conversion may fail, or an unrecoverable readfrom (write to) external device occurs. Such failures indicate loss of integrity.Generally, badbit indicates an errorsituation that is likely to be unrecoverable, whereas failbitindicates a situation that might be recoverable on retrying the failedoperation. The flag eofbit just indicates that the end of the inputsequence was reached.

 

To detect stream errors, there are two possibilities:

 

1.     Handle an exception raisedonce an error occurs in any input or output operation

2.     Check the stream state after each input oroutput operation by calling various boolean returning member functions

 

Following table shows boolean returning stream member functions for error checking:

 

ios member function Effect
operator ! () Returns true when operation has failed,
Ex. if (!cout) { // error }
fail() Same as operator !(), Returns true if failbit or badbit is set
operator void * () Returns false if fail() and true otherwise,
Ex. if (cout) {//no error }
good() Returns true if no error flag is set, i.e. goodbit is set
eof() Returns true if eofbit is set
bad() Returns true if badbit is set
iostate rdstate() Returns enum value of stream state
clear() Clears all flags, set state as good
clear (iostate state) Set the stream state to the argument state
#include <iostream>
int main()
{
int x;
cout << “Enter an integer: “;

 

cin >> x;

ios::iostate flags = cin.rdstate();  //get stream state

if (flags & ios::failbit)          // if cin.fail()

cout << “failbit set.” << endl;

else

cout << “failbit not set.” << endl;

if (flags & ios::badbit) // if cin.bad()
cout << “badbit set.” << endl;
else
cout << “badbit not set.” << endl;
if (flags & ios::eofbit) // if eof()

cout << “eofbit set.” << endl;

else

cout << “eofbit not set.” << endl;

 

//  test the bits directly: if (cin.good())

cout << “Stream state is good.” << endl; else

cout << “Stream state is not good.” << endl; if (cin.fail())

cout << “Are you sure you entered an integer?” << endl; else

cout << “You entered: ” << x << endl;

}

 

Remember that once the failbit is set while performing input/output, it remains in effect. To reset all bits of error-status flag, one should use clear() function.

 

Summary

 

  •  User specified formattingallows alignment, decimal-point alignment, width specification etc.
  • Formatting is controlled using state variables (for width, fill character and precision) and format flag.
  • The bits of formatting flag acts as on/off switches. Different bits are used to specify alignment, integer number representation, floating point representation, forced decimal point, showing + sign before number etc.
  • The bits of formatting flag and the values of format state variables can be set/reset or get using member functions of ios class and also by using manipulators.·
  •    Using member functions of ios class
  •    Values of state variables can be set/get using width(), fill() and precision().
  • The bits of formatting flag can be set/reset using setf(), unsetf() and flag().
  • Function setf() and unsetf() can be used to set/reset specific bits of formatting flag; whereas function flag() can be used to set/get all bits of formatting flag at a time.
  • The effect of setting a format is permanent except in case of the field width. The width is automatically reset to its default value 0 after each use.

·      Width parameter

  •  It specifies the minimum width to be used. If an item requires more width, the specified width argument is ignored.
  •  Default width is zero.
  •  While reading numbers, it does not use width parameter. Extraction stops at white space or any invalid character.
  •  Fillparameter specifies the character to be used as padding character to fill extra positions. Default fill character is space.
  • Precision parameter
  • It specifies the number of significant digits in case of floating point numbers.
  • Default precision is 6.
  • When specified precision is not enough to accommodate number of digits after decimal point, the value is rounded
  • When specified precision is not enough to accommodate integral portion of a number, it uses scientific format.
  • Formatting using manipulators
    • o Manipulators setw(), setfill() and setprecision() are used to set the values of format state variables; whereas setiosflags(), resetiosflags() are used to set and reset formatting flags.
  • o Advantages
    • Can be used with shift operator in cascaded fashion
    • Do not require to be called using dot operator with stream objects
    • Can be defined by users
  • Error-status falg
    • o Each stream has an error state that identifies whether an I/O operation was successful or not.
  • o Some of the error-status flags are goodbit, badbit, failbit, eofbit.
  • o Status bits can be tested using stream member functions like good(), bad(), fail(), eof().
  • Once the error bit is set, it remains in effect. Function clear() should be used to clear/reset all bits of error-status flags.

Additional References

 

1) Stanley Lippmann, “C++ Primer”, Pearson Education.

2) Bjarne Stroustrup, “The C++ Programming Language”, Pearson Education.

3) Scott Mayer, “Effective C++”, Addison Wesley.

4) Bhushan Trivedi , Programming with ANSI C++, 2/e , Oxford University Press.

5) Yashavant P. Kanetkar “Let Us C++” , Bpb Publications.

6) Abhiram G. Ranade, “An Introduction to Programming through C++” , McGraw Hill

7) Ellis and B. Stroustrup “Annotated C++ Reference Manual”, http://www.stroustrup.com/arm.html

8) Herbert Schildt, “Complete Reference C++”, McGraw Hill Publications.

9) Ashok Kamthane, “Object Oriented Programming with ANSI and Turbo C++”, Pearson Education

10) E Balaguruswami, “Object Oriented Programming With C++”, Tata McGraw Hill

11) “C++ FAQs”, Pearson Education.