Useful Classes and Functions - I


The following topics are covered in this section:


There are two ways in which we can perform stream-formatting operations: using manipulators or using the stream member functions.

Manipulators

There are many stream-formatting functions available but it is a little tedious to use them. Manipulators duplicate these functions and make it easier to carry out stream-formatting operations. Usually it is the output (what we display on the screen) that needs to be formatted to suit our needs. In this case, ‘cout’ is the stream.

One of the most commonly used manipulators is ‘endl’. This is used to end the current line and go to the next line. You cannot use ‘endl’ separately. All the manipulators have to operate on streams. Manipulators that do not require any arguments are defined in the iostream.h header (manipulators with arguments are defined in the iomanip.h header file).

Let's check out an example program.

# include<iostream.h>
int main( )
{
cout<< "Hi, this is a test program"<<endl;
cout<<endl;
cout<<endl<<"You should see three empty lines above this";
return 0;
}

The output will be:

Hi, this s a test program



You should see three empty lines above this

Each ‘endl’ will cause the present line to be terminated and hence, there will be three empty lines in between the two sentences.

Remember: Don't use double quotes on endl.

The above program can also be written as:

cout<< "Hi, this is a test program"<<endl<<endl<<endl<<"You should see three empty lines above this";

The output will be the same since manipulators can be cascaded in a single statement.

Flushing and Buffer:

Actually endl is equivalent to writing:

cout<<"\n";

This is called as the newline character. But the ‘endl’ manipulator does something more than just inserting a newline character. It will also flush the stream. When you write something to a stream, data is first written into a buffer (stream buffer called as streambuf) and then from there into your stream (this will happen automatically and it may seem as if the data is being directly written to the stream). Data will be written to the stream only when the buffer is full. When a stream is flushed, all the pending data present in the buffer (which hasn’t been used as yet) will be flushed from the buffer to the stream. A buffer is a temporary intermediate storage area used when information is transferred between a stream and a file. The ‘ostream’ has a member function called flush( ). To flush a stream you can either type:

cout.flush( );

or you can use the manipulator:

cout<<flush;

The OS will have its own buffer to improve efficiency but through C++ you can only control the buffers created by your code (i.e. streambuf). Why do we need buffers? Every stream is associated to some physical device (a simple example is that of streams being associated to files). The stream buffer will be tuned to the physical device associated to the stream. Most of the physical devices are much slower than memory access (i.e. memory operations are much faster than I/O device operation). Now if buffers are not used then the processor will waste a considerable amount of time in waiting for something to happen in the I/O device. For example when we enter something through a keyboard, there is a considerable delay between two keystrokes; maybe just a fraction of a second but this time can be used by the computer to perform its internal operations instead of waiting for the user to type something. This is where buffer comes into the picture. A buffer will keep collecting the data (it is like a storage area) till it gets full. Once the buffer is full it will flush the data to the corresponding stream. Once again the buffer will start collecting new data till it gets full and the process repeats.

Using the flush ( ) function, you can forcefully flush data into the stream continuously (instead of waiting till the buffer gets full). A simple program should make the concept of buffering and flushing clear. Let us write a program to write the number 12 to a disk file (using streams).

# include <iostream.h>
#include <fstream.h>
#include <stdlib.h>

int main( )
{
ofstream out("c:\\test.txt",ios::binary);
out<<12;
system("PAUSE");
out.close( );
return 0;
}

When the program executes:

out<<12;

It will not write the number ‘12’ to the file test.txt. To verify this run your program in windows. While the program is running, because of:

system("PAUSE");

The program will pause for the user to press a key. Now go to the desktop, open "My Computer" and in C: drive open the file test.txt (or open this file from ‘Notepad’). You will notice that the file is empty. Thus, though we think that 12 has been written to the file, in reality it hasn’t been written as yet. The number ‘12’ is still in the buffer. Close the Notepad and press a key to continue the execution of the program. After execution once again open the file test.txt in Notepad and you will see 12 written in the file. Thus since the buffer was not full (because we wanted to write only a small number to the file) the data was not written immediately. Instead the buffer waited hoping that more data would be entered. But when out.close( ) was encountered it knew that now it had to flush the data from the stream (because the stream is going to be disassociated from the file). To instantly update the file, we can make use of the flush( ) function as shown below:

# include <iostream.h>
#include <fstream.h>
#include <stdlib.h>

int main( )
{
ofstream out("c:\\test.txt",ios::binary);
out<<12;
out.flush( );                             //12 is written immediately to the file
system("PAUSE");
out.close( );
return 0;
}

In the above program we forcefully flush the stream and data is immediately written to the file. Flushing forcefully is useful in situations where you need to update the file continuously (when there is likeliness of frequent power shortages etc.) otherwise you might lose the data present in the buffer.


setw( )

This manipulator is used to set the width of the data being displayed. If the data is longer than the width you specify, this manipulator will not truncate your data to fit the width. Instead it will display the entire data but this will lead to misalignment. The setw( ) manipulator defined in the <iomanip.h> header since it takes arguments.

#include <iostream.h>
#include <iomanip.h>

int main( )
{
cout<<endl<<"James"<<setw(20)<<"Harry"<<setw(4)<<"Joe";
return 0;
}

The output is:

        James         Harry Joe

The diagram should make it clear as to how the setw( ) works.

The statement:

cout<<setw(20)<<"Harry";

means that the word Harry will be given an alignment of 20 characters and Harry will be starting from the right end (as shown in figure). The net result is that we will have 15 blank whitespaces between ending of James and the starting of Harry.

Setprecision( )This also comes under the iomanip header. It is used to set the number of decimal places that you would like to view in your output.

Example:

#include <iostream.h>
#include <iomanip.h>

int main( )
{
cout<<setprecision(3)<<3.456<<endl<<setprecision(1)<<3.14213;
return 0;
}

Output is:

3.46
3

You can see that the result gets rounded up to the number of places that you want. 3.456 is displayed as 3.46 because we set the precision to 3 digits only.

The other manipulators available in <iostream.h> are:

Name of the Manipulator

Purpose

ends

Inserts a null character (‘\0’)

dec

Display integer in base 10

oct

Display integer in base 8

hex

Display integer in base 16

ws

Skip whitespace in input stream

flush

Flush the stream

The manipulators available in <iomanip.h> are (these manipulators require arguments):

Name of the Manipulator

Purpose

setiosflags(names-of-flags) Set formatting flags
resetiosflags(names-of-flags) Reset formatting flags
setbase(int base) where base=8,10 or 16
setfill (char c) Uses ‘c’ as the fill character
setprecision (int n) Changes precision to ‘n’
setwidth (int n) Width set to ‘n’

In the table above ‘names-of-flags’ refers to the formatting flags that can be set/reset depending on which manipulator you use. If a formatting flag is set then that particular format will be active (or effective). The formatting flags are tabulated below:

Name of the Formatting Flag

Purpose

ios::showbase display an integer’s base
ios::showpos indicates positive numbers by using the + sign
ios::skipws skip whitespaces
* ios::dec display integers in base 10.
ios::hex display integer in base 16
ios::oct display integer in base 8
*ios::fixed use fixed notation for displaying floating point numbers
ios::scientific use scientific notation (i.e. using exponential)
*ios::left align left
ios::right align right

* indicates that these flags are already set by default.

By the way, these flags are usually known as IOS Formatting flags. If you want to play around with these flags, then you should make use of

setiosflags(names-of-flags)

or

resetiosflags(names-of-flags)

An example to illustrate the use of these formatting flags is given below:

#include <iostream.h>
#include <iomanip.h>

int main( )
{

cout<<setiosflags(ios::showpos)<<20;
cout<<endl<<setiosflags(ios::scientific);
cout<<300.4567;
return 0;

}

The output is:

+20
+3.004567e+002

Beware: All the formatting flags come under the namespace std::ios::

This is why we have used ios::scientific and ios::showpos. This will be dealt with in the section on ‘namespaces’.


Go back to the Contents Page 2


Copyright © 2004 Sethu Subramanian All rights reserved.