C++ Ripped Apart :: Section 3
Author: Mike Ware
Website: [warebiz] :: "The Programmer's Domain" - http://warebiz.tripod.com
Email: warebiz@yahoo.com

You are here --> [Section 3 :: Manipulating Control Structures and Formatting Output]

--> Using Sentinel Values
--> Using Counters
--> Output Manipulators

Using Sentinel Values

There are three methods used to control repetition during execution of a program: sentinel values, prime reads, and counters. 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 don't exactly know how many times a user needs to enter data for a particular item. When the user is done entering information, the user can enter a sentinel value, which will tell the program that 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 during repetitive statements.
<<<<<<<<<

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

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

int main()
{
int age, sumOfAges = 0;

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

if (sumOfAges == 0)
cout << "No data entered." << endl << endl;
else
cout << "The sum of all ages inputted is: " << sumOfAges << endl << endl;

system("PAUSE");
return EXIT_SUCCESS;
}
```

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

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

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

int main()
{
int numScores = 0, sum = 0, score;
float average;

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

if (sum == 0)
cout << "No data entered." << endl << endl;
else
{
average = float(sum) / numScores;
cout << "The average of the " << numScores << " was " << average << endl << endl;
}

system("PAUSE");
return EXIT_SUCCESS;
}
```

Another method used to control 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 prime read

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

int main()
{
int age, sumOfAges = 0;

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

if (sumOfAges == 0)
cout << "No data entered." << endl << endl;
else
cout << "The sum of all ages inputted is: " << sumOfAges << endl << endl;

system("PAUSE");
return EXIT_SUCCESS;
}
```

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

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

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

int main()
{
int numScores = 0, sum = 0, score;
float average;

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

if (sum == 0)
cout << "No data entered." << endl << endl;
else
{
average = float(sum) / numScores;
cout << "The average of the " << numScores << " was " << average << endl << endl;
}

system("PAUSE");
return EXIT_SUCCESS;
}
```

We have now 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 a program to input ten numbers, you could set a counter variable to 0, and then set up a loop to continue cycling while the value of counter is less than ten (this loop would iterate ten times: 0, 1, 2, .., 9).

Example 1:

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

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

int main()
{
int count = 0, numTimesNeeded = 10;

while ( count < numTimesNeeded )
{
cout << count + 1 << endl;
count++;
}

cout << endl << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
```

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:

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

int main()
{
int count = 0, score, numTimesNeeded = 10, total = 0;
float average;

while ( count < numTimesNeeded )
{
cout << "Enter score for test " << count + 1 << ": ";
cin >> score;
total += score;
count++;
}

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

system("PAUSE");
return EXIT_SUCCESS;
}
```

We have now covered three methods of controlling repetition: using a sentinel value, prime read, or counter. It's time to move on and cover how programmers control output using output manipulators. Read on for more about ways to structure 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 assuming you are using a version of DEV's C/C++ compiler so if you are using a different compiler, you might see some slight differences 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.
setflag sets a formatting flag.

Options
showpoint - instructs the compiler to display a decimal point and any trailing zeros; only defined for floating point values and never influences an integer value.

showpos - instructs 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, determines how many values to be displayed after the decimal; if used without fixed, 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 field 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 learn output manipulators is by examining examples and performing experimentation. 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.

```
////////////////////////////////////////// USING DEV C/C++ V.4 COMPILER /////////////////////////////////////////////

#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 << endl << endl;

system("PAUSE");
return EXIT_SUCCESS;
}

////////////////////////////////////////// USING DEV C/C++ V.4 COMPILER /////////////////////////////////////////////
```

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

///////////// END EXAMPLE PROGRAM /////////////

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. The easiest way to become familiar with them is by performing tests. 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 file streams allow programs to interact with data stored on a hard drive. Read on for more about files...

Move on to next set of topics: [Section 4] - Text Files, Strings, Random Numbers, and Member Functions