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...
Comments