Programming in C++

Control Structures and Formatting Output

Using Sentinel Values

There are three ways to control repetition during execution of a program: sentinel values, prime reads, and counters. Let's talk about sentinel values now and talk about prime reads and counters later. A sentinel value is a value that is not a legitimate data value for a particular problem (but is of proper type) used to check for a "stopping" value. There may be times when you must let users of your program enter as much information about something as they want to. When the user is done entering information, the user can enter a sentinel value, which would let the program know when the user is done inputting information.

Definition - sentinel value - a value that is not a legitimate data value (but is of proper type) used to check for a "stopping value".

Example 1: [ -1 ] is used as a sentinel value

   int age;
   cout << "Enter an age ( -1 to stop ): ";
   cin >> age;
   while ( age != -1 )
   {
           .
           .
           .
           cout << "Enter an age ( -1 to stop ): ";
           cin >> age;
   }


Example 2: [ -99 ] is used as a sentinel value

Read a list of text scores and calculate their average. An input of -99 for a score denotes end-of-data for the user.

   int numScores, sum, score;
   float average;
   sum = 0;
   numScores = 0;

   cout << "Enter a test score ( -99 to quit ): ";
   cin >> score;
   while ( score != -99 )
   {
           sum += score;
           numScore++;
           cout << "Enter a test score ( -99 to quit ): ";
           cin >> score;
   }

   average = float(sum) / numScores;
   cout << "The average of the " << numScores << " was " << average << endl << endl;


The next article will introduce you to prime reads. Prime reads and sentinel values normally go hand and hand, but not for every situation. Read on to learn more about prime reads...

Using Prime Reads

Another method of controlling repetition is to use a prime read. A prime read and sentinel value often go hand and hand but not always. A prime read is a data input, before the loop statement, that allows the first actual data value to be entered so it can be checked in the loop statement. The variable that is inputted by the user and being tested by the expression in the loop is the prime read; the value of the prime read is what we call a sentinel value [ see Using Sentinel Values].

Example 1: [ age ] is used as a prime read

   int age;
   cout << "Enter an age ( -1 to stop ): ";
   cin >> age;
   while ( age != -1 )
   {
           .
           .
           .
           cout << "Enter an age ( -1 to stop ): ";
           cin >> age;
   }


Example 2: [ score ] is used as a prime read

Read a list of text scores and calculate their average. An input of -99 for a score denotes end-of-data for the user.

   int numScores, sum, score;
   float average;
   sum = 0;
   numScores = 0;

   cout << "Enter a test score ( -99 to quit ): ";
   cin >> score;
   while ( score != -99 )
   {
           sum += score;
           numScore++;
           cout << "Enter a test score ( -99 to quit ): ";
           cin >> score;
   }

   average = float(sum) / numScores;
   cout << "The average of the " << numScores << " was " << average << endl << endl;


We've covered sentinel values and prime reads, but there is one last method used for controlling repetition during execution of a program. Read on to learn more about using counters...

Using Counters

Yet another method for controlling repetition during execution of a program is by using a counter. Using a counter requires knowledge of the exact number of times you need to repeat something. For example, if you were to instruct the user of your program to input ten numbers, you could set a counter variable to 0, and then set up a loop to continue cycles while the value of counter is less than ten (this loop would equal ten cycles: 0, 1, 2, .., 9).

Example 1:

Write a section of code that would output the numbers from 1 to 10:

   int count;
   count = 0;
   int numTimesNeeded = 10;
   while ( count < numTimesNeeded )
   {
           count << count + 1 << endl;
           count++;
   }


Example 2:

Write a section of code that will allow the user to input ten test scores in order to find the average of the scores:

   int count, score;
   float average;
   count = 0;
   int numTimesNeeded = 10;
   int total = 0;
   while ( count < numTimesNeeded )
   {
           cout << "Enter the score for test " << count + 1 << ": ";
           cin >> score;
           total += score;
           count++;
   }

   average = float(total) / numTimesNeeded;
   cout << "The average of the " << numTimesNeeded << " test scores is: " << average << endl;


We have now covered three ways of controlling repetition: using a sentinel value, prime read, or counter. It's time to move on and talk about how programmers control output using output manipulators. Read on for more about ways to spice up your form of output...

Output Manipulators

There may be many reasons why you would want to override the default output behavior. Maybe you are outputting the totals for certain customers at a store and you need to allow just two digits after the decimal point. Output manipulators allow programmers to control the exact form of output. I've found that these manipulators vary from compiler to compiler. I'm basing the information in this tutorial from using Dev's compiler so if you are using a different compiler, you might see some slight changes in the form of your output. Most manipulators are found in the header file    #include <iomanip.h>    but that may also vary from compiler to compiler. Remember that header files are placed at the beginning of your source code after the documentation of your program. The following are some examples of output manipulators:

When turning on certain options, you must use one the following forms before outputting:

   1 - cout.setf( ios::option here | ios::option here );
   2 - cout << setiosflags( ios::option here | ios::option here );

There is also a way to turn off options if you wish to terminate them after using them:

   cout << resetiosflags( ios::option here | ios::option here );

Overview of Statement Commands

cout is an object.
setf is a member function.
ios is a class.
:: is a scope resolution operator.
| is the bitwise OR operator.
object is a class variable.
setflag sets a formatting flag.

Options

showpoint - tells the compiler to display a decimal point and any trailing zeros; only defined for floating point values and never influences an integer value.
showpos - tells the compiler to display a "+" to the left of all positive values.
fixed - tells the compiler how many values to display after the decimal point in order to fulfill default number of significant digits.
scientific - converts values into scientific notation while also having the abilities of fixed
left - sets left justification.
right - sets right justification (default).

Example 1:

Write code to turn on the following flags: showpoint, fixed, left (you have 2 options)

   1 - cout << setiosflags ( ios::showpoint | ios::fixed | ios::left );
   2 - cout.setf ( ios::showpoint | ios::fixed | ios::left )

Other Manipulators

setprecision( ) - If used with fixed it determines how many values to be displayed after the decimal; if used without fixed it determines how many significant digits to be displayed.

setw ( ) - Determines the width of the output field. Its effect does not "stick" throughout the rest of the statement; it is only good for the value it precedes. You must set a width for every value that you want to control.

setfill ( char ) - Specifies a char to be used instead of blank spaces when an output field is larger than the required size. You must turn it off by setting the fill to be spaces if you wish to get back to filling with blank spaces.

The best way to see how manipulators are used is to examine examples and fool around with them yourself. By default, Dev's compiler displays at most 6 significant digits. Let's examine the source code of a complete program and study the program's output.

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

void main ( )
{
   float x = 23.012345678;
   float y = 44;
   float z = 3.765;
   float a = 4.5;

   cout << 2345.012345678 << endl;
   cout << 0.005544332211 << endl;
   cout << x << endl;
   cout << y << endl;
   cout << z << endl;
   cout << a << endl;
   cout << x << y << z << a << endl;

   system("PAUSE");
   return 0;
}


Output produced by program:

2345.01
0.00554433
23.01234
44
3.765
4.5
23.0123443.7654.5


Add the following piece of code before the cout statements above:

cout.setf ( ios::showpoint | ios::showpos );

New output produced by program:

+23.0123
+44
+3.76500
+4.50000
+23.0123+44+3.76500+4.50000


Now add the following before the cout statements above:

setprecision (2);


New output produced by program:

+23.
+44
+3.8
+4.5


Change the last cout statement to:

cout << x << setfill ( '*' ) << setw ( 10 ) << y << setfill ( ' ' ) << z << a << endl;

Output produced:

+23.0123*******+44+3.76500+4.50000


Change the last cout statement to:

cout << x << setfill ( '*' ) << setw ( 10 ) << y << setw ( 10 ) << z << setw ( 10 ) << a << endl;

Output produced:

+23.0123*******+44**+3.76500**+4.50000

Example code:

   const float PI = 3.14159;
   cout << setiosflags ( ios::showpoint ) << endl << "The value of PI is: "
       << setprecision ( 4 ) << setw ( 15 ) << setfill ( '-' ) << PI << endl;


Output produced:         ----------3.142

Add the fixed manipulator option to the code:

   setiosflags ( ios::showpoint | ios::fixed );


New output produced:         ---------3.1416

Change code to:

   setiosflags ( ios::showpoint | ios::scientific );

New output produced:         -----3.1416e+00

Change code to:

   setiosflags ( ios::showpoint | ios::scientific | ios::left );


New output produced:         3.1416e+00-----

We covered a good bit of information about output manipulators, but the best way to get familiar with them is to fool around with them yourself. Experiment a little bit. Experimentation gives birth to knowledge. Now it's time to move on to a subject that I find interesting compared to the previous articles: files. I like working with files for the simple fact that the code you write is capable of reading data from your computer's hard drive and also saving data to the hard drive. Read on for more about files...

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The generation of random numbers is too important to be left to chance.” - Robert R. Coveyou