nut fell off, and it looped from one lug nut to the other until the entire wheel
came off. This chapter introduces you to two of the three looping constructs
in C++.Creating a while LoopThe while loop has the following format:while (expression){
// stuff to do in a loop
}
// continue here once expression is falseWhen a program comes upon a while loop, it first evaluates the expressionin the parentheses. If this expression is true, then control passes to the firstline inside the {. When control reaches the }, the program returns back tothe expression and starts over. Control continues to cycle through the code
in the braces until expression evaluates to false (or until something elsebreaks the loop — more on that a little later in this chapter).
100 Part III: Becoming a Functional ProgrammerThe following Factorial program demonstrates the while loop:Factorial(N) = N * (N-1) * (N-2) * ... * 1//// Factorial - calculate factorial using the while// construct.//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int nNumberofArgs, char* pszArgs[])
{
// enter the number to calculate the factorial of
int nTarget;
cout << “This program calculates factorial.\n”
<< “Enter a number to take factorial of: “;
cin >> nTarget;
// start with an accumulator that’s initialized to 1
int nAccumulator = 1;
int nValue = 1;
while (nValue <= nTarget)
{
cout << nAccumulator << “ * “
<< nValue << “ equals “;
nAccumulator = nAccumulator * nValue;
cout << nAccumulator << endl;
nValue++;
}
// display the result
cout << nTarget << “ factorial is “
<< nAccumulator << endl;
// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}The program starts by prompting the user for a target value. The program readsthis value into nTarget. The program then initializes both nAccumulatorand nValue to 1 before entering the loop.(Pay attention — this is the interesting part.) The program compares nValueto nTarget. Assume that the user had entered a target value of 5. On thefirst loop, the question becomes, “Is 1 less than or equal to 5?” The answer is
Chapter 9: while Running in Circles 101obviously true, so control flows into the loop. The program outputsthe value of nAccumulator (1) and nValue (also 1) before multiplyingnAccumulator by nValue and storing the result back into nAccumulator.The last statement in the loop increments nValue from 1 to 2.That done, control passes back up to the while statement where nValue(now 2) is compared to nTarget (still 5). “Is 2 less than or equal to 5?”Clearly, yes; so control flows back into the loop. nAccumulator is now set tothe result of nAccumulator (1) times nValue (2). The last statement increments nValue to 3.This cycle of fun continues until nValue reaches the value 6, which is nolonger less than or equal to 5. At that point, control passes to the first statement beyond the closed brace }. This is shown graphically in Figure 9-1.Figure 9-1:Controlcontinues
to cycle
through
the body of
a whileloop untilthe conditional
expression
evaluates tofalse.while (nValue <= nTarget){
cout << nAccumulator << " * "
<< nValue << " equals ";
nAccumulator = nAccumulator * nValue;
cout << nAccumulator << endl;
nValue++;
}For nValue <= nTarget is truewhile (nValue <= nTarget)
| { | cout << nAccumulator << " * "For nValue <= nTarget is false |
cout << nAccumulator << endl;
nValue++;
}The actual output from the program appears as follows for an input value of 5:This program calculates factorial.Enter a number to take factorial of: 51 * 1 equals 11 * 2 equals 2
2 * 3 equals 6
6 * 4 equals 24
24 * 5 equals 120
5 factorial is 120
Press any key to continue . . .
102 Part III: Becoming a Functional ProgrammerYou are not guaranteed that the code within the braces of a while loop isexecuted at all: If the conditional expression is false the first time it’s evaluated, control passes around the braces without ever diving in. Consider, for
example, the output from the Factorial program when the user enters a target
value of 0:This program calculates factorial.Enter a number to take factorial of: 0
0 factorial is 1
Press any key to continue . . .No lines of output are generated from within the loop because the condition“Is nValue less than or equal to 0” was false even for the initial value of 1.The body of the while loop was never executed.Breaking out of the Middle of a LoopSometimes the condition that causes you to terminate a loop doesn’t occuruntil somewhere in the middle of the loop. This is especially true when testing user input for some termination character. C++ provides these two control commands to handle this case:✓ break exits the inner most loop immediately.✓ continue passes control back to the top of the loop.The following Product program demonstrates both break and continue.This program multiplies positive values entered by the user until the user
enters a negative number. The program ignores zero.//// Product - demonstrate the use of break and continue.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int nNumberofArgs, char* pszArgs[])
{
// enter the number to calculate the factorial of
cout << “This program multiplies the numbers\n”
<< “entered by the user. Enter a negative\n”
<< “number to exit. Zeroes are ignored.\n”
<< endl;
int nProduct = 1;
while (true)
{
Chapter 9: while Running in Circles 103int nValue;cout << “Enter a number to multiply: “;
cin >> nValue;
if (nValue < 0)
{
cout << “Exiting.” << endl;
break;
}
if (nValue == 0)
{
cout << “Ignoring zero.” << endl;
continue;
}
// multiply accumulator by this value and
// output the result
cout << nProduct << “ * “ << nValue;
nProduct *= nValue;
cout << “ is “ << nProduct << endl;
}
// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}The program starts out with an initial value of nProduct of 1. The programthen evaluates the logical expression true to see if it’s true. It is.There aren’t too many rules that hold in C++ without exception, but here’s
one: true is always true.The program then enters the loop to prompt the user for another value to
multiply times nProduct, the accumulated product of all numbers enteredso far. If the value entered is negative, then the program outputs the phrase“Exiting.” before executing the break, which passes control out of the loop.If the value entered is not negative, control passes to the second if statement.If nValue is equal to zero, then the program outputs the messages “Ignoringzero.” before executing the continue statement which passes control backto the top of the loop to allow the user to enter another value.
If nValue is neither less than zero nor zero, then control flows down towhere nValue is multiplied by nProduct using the special assignment operator (see Chapter 4 if you don’t remember this one):nProduct *= nValue;104 Part III: Becoming a Functional ProgrammerThis expression is the same as:nProduct = nProduct * nValue;The output from a sample run from this program appears as follows:This program multiplies the numbersentered by the user. Enter a negative
number to exit. Zeroes are ignored.
Enter a number to multiply: 21 * 2 is 2Enter a number to multiply: 52 * 5 is 10Enter a number to multiply: 0Ignoring zero.Enter a number to multiply: 310 * 3 is 30Enter a number to multiply: -1Exiting.Press any key to continue . . .Why is “break” necessary?You might be tempted to wonder why break is really necessary. What if I had coded the loop in
the Product example program asint nProduct = 1;int nValue = 1;
while (nValue > 0)
{
cout << “Enter a number to multiply: “;
cin >> nValue;
cout << nProduct << “ * “ << nValue;
nProduct *= nValue;
cout << “ is “ << nProduct << endl;
}You might think that as soon as the user enters a negative value for nValue, the expressionnValue > 0 is no longer true and control immediately exits the loop — unfortunately, this is
not the case.
The problem is that the logical expression is only evaluated at the beginning of each pass through
the loop. Control doesn’t immediately fly out of the body of the loop as soon as the condition ceases
to be true. An if statement followed by a break allows me to move the conditional expression
into the body of the loop where the value of nValue is assigned.
Chapter 9: while Running in Circles 105
Nested LoopsThe body of a loop can itself contain a loop in what is known as nested loops. Theinner loop must execute to completion during each time through the outer loop.
I have created a program that uses nested loops to create a multiplication
table of the form:0 1 2 3 4 5 6 7 8 90 0*0 0*1 0*2 0*3 0*4 0*5 0*6 0*7 0*8 0*9
1 1*0 1*1 1*2 1*3 1*4 1*5 1*6 1*7 1*8 1*9
2 2*0 2*1 2*2 2*3 2*4 2*5 2*6 2*7 2*8 2*9
//... and so on...You can see that for row 0, the program will need to iterate from column 0through column 9. The program will repeat the process for row 1 and again for
row 2 and so on right down to row 9. This implies the need for two loops: an inner
loop to iterate over the columns and a second outer loop to iterate over the rows.
Each position in the table is simply the row number times the column number.
This is exactly how the following NestedLoops program works://// NestedLoops - this program uses a nested loop to
// calculate the multiplication table.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int nNumberofArgs, char* pszArgs[])
{
// display the column headings
int nColumn = 0;
cout << “ “;
while (nColumn < 10)
{
// set the display width to two characters
// (even for one digit numbers)
cout.width(2);
// now display the column number
cout << nColumn << “ “;
// increment to the next column
nColumn++;
}
cout << endl;
// now go loop through the rows
int nRow = 0;
106 Part III: Becoming a Functional Programmerwhile (nRow < 10){
// start with the row value
cout << nRow << “ - “;
// now for each row, start with column 0 and
// go through column 9
nColumn = 0;
while(nColumn < 10)
{
// display the product of the column*row
// (use 2 characters even when product is
// a single digit)
cout.width(2);
cout << nRow * nColumn << “ “;
// go to next column
nColumn++;
}
// go to next row
nRow++;
cout << endl;
}
// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}The first section creates the column headings. This section initializes nColumnto 0. It then iterates through nColumn printing out its value separated bya space until nColumn reaches 10. At this point, the program exits the firstloop and then tacks a new line on the end to finish the row. This is shown
graphically in Figure 9-2.
Executing just this section alone generates the following output:0 1 2 3 4 5 6 7 8 9This program demonstrates an unfair advantage that I have. The expressioncout.width(2) sets the display width to two columns — C++ will pad aspace on the left for single-digit numbers. I know it’s cheating to make use of
a feature that I don’t present to the reader until Chapter 31, but it’s very difficult to get the columns to line up without resorting to fixed-width output.
The second set of loops, the nested loops, starts at nRow equal to 0. The program prints out the row number followed by a dash before launching into aChapter 9: while Running in Circles 107second loop that starts nColumn at 0 again and iterates it back up to 9. Foreach pass through this inner loop, the program sets the output width to two
spaces and then displays nRow * nColumn followed by a space.Figure 9-2:The firstloop outputs
the column
headings.// display the column headingsint nColumn = 0;
while (nColumn < 10)
{
// now display the column number
cout << nColumn << " ";
// increment to the next column
nColumn++;
}
//go to the next row
cout << end1;Output: 0 1 2 3 4 5 6 7 8 9The display width resets itself each time you output something, so it’s necessary to set it back to two each time before outputting a number.The program outputs a newline to move output to the next row each time it
increments nRow. This is shown graphically in Figure 9-3.The output from this program appears as follows:0 1 2 3 4 5 6 7 8 90 - 0 0 0 0 0 0 0 0 0 0
1 - 0 1 2 3 4 5 6 7 8 9
2 - 0 2 4 6 8 10 12 14 16 18
3 - 0 3 6 9 12 15 18 21 24 27
4 - 0 4 8 12 16 20 24 28 32 36
5 - 0 5 10 15 20 25 30 35 40 45
6 - 0 6 12 18 24 30 36 42 48 54
7 - 0 7 14 21 28 35 42 49 56 63
8 - 0 8 16 24 32 40 48 56 64 72
9 - 0 9 18 27 36 45 54 63 72 81
Press any key to continue . . .There is nothing magic about 0 through 9 in this table. I could just have easilycreated a 12 x 12 multiplication table (or any other combination) by changing
the comparison expression in the three while loops. However, for anythinglarger than 10 x 10, you will need to increase the minimum width to accommodate the three-digit products. Use cout.width(3).108 Part III: Becoming a Functional ProgrammerFigure 9-3:The innerloop iterates
from left to
right across
the columns, while
the outer
loop iterates
from top
to bottom
down the
rows.// now go loop through the rows
int nRow = 0;
while (nRow < 10)
{
// start with the row value
cout << nRow << " – ";
// now for each row, start with column 0 and
// go through column 9
nColumn = 0;
while(nColumn < 10)
{
cout << nRow * nColumn << " ";
// go to next column
nColumn++;
}
// go to next row
nRow++;
cout << end1;
}0 * 0 0 * 1 0 * 2 0 * 3 0 * 4 0 * 5 0 * 6 0 * 7 0 * 8 0 * 9
1 * 0 1* 1 1 * 2 1 * 3 1 * 4 1 * 5 1 * 6 1 * 7 1 * 8 1 * 9
2 * 0 2 * 1 2 * 2 2 * 3 2 * 4 2 * 5 2 * 6 2 * 7 2 * 8 2 * 9Output:Inner loop
Outer
loop
Chapter 10Looping for the Fun of ItIn This Chapter▶ Introducing the for loop▶ Reviewing an example ForFactorial program▶ Using the comma operator to get more done in a single for loopThe most basic of all control structures is the topic of Chapter 9. This chapter introduces you its sibling, the while loop, which is the for loop.Though not quite as flexible, the for loop is actually the more popular of thetwo — it has a certain elegance that is hard to ignore.The for Parts of Every LoopIf you look again at the examples in Chapter 9, you’ll notice that most loopshave four essential parts. (This feels like breaking down a golf swing into its
constituent parts.)✓ The setup: Usually the setup involves declaring and initializing anincrement variable. This generally occurs immediately before thewhile.✓ The test expression: The expression within the while loop that willcause the program to either execute the loop or exit and continue
on. This always occurs within the parentheses following the keywordwhile.✓ The body: This is the code within the braces.✓ The increment: This is where the increment variable is incremented.This usually occurs at the end of the body.
In the case of the Factorial program, the four parts looked like this:int nValue = 1; // the setupwhile (nValue <= nTarget) // the test expression
{ // the body
cout << nAccumulator << “ * “
110 Part III: Becoming a Functional Programmer<< nValue << “ equals “;nAccumulator = nAccumulator * nValue;
cout << nAccumulator << endl;
nValue++; // the increment
}The for loop incorporates these four parts into a single structure using thekeyword for:for(setup; test expression; increment){
body;
}The flow is shown graphically in Figure 10-1.1. As the CPU comes innocently upon the for keyword, control is divertedto the setup clause.2. Once the setup has been performed, control moves over to the testexpression.3. (a) If the test expression is true, control passes to the body of thefor loop.(b) If the test expression is false, control passes to the next statement after the closed brace.4. Once control has passed through the body of the loop, the CPU is forced
to perform a U-turn back up to the increment section of the loop.That done, control returns to the test expression and back to Step 3.Figure 10-1:The flow inand around
the forloop.for(setup; test expression; increment)
| { | 3a - if test expression is true3b - if test expression is |
| falsebody; |
5
Chapter 10: Looping for the Fun of It 111This for loop is completely equivalent to the following while loop:setup;while(test expression)
{
body;
increment;
}Looking at an ExampleThe following example program is the Factorial program written as a for loop(this program appears on the enclosed CD-ROM as ForFactorial)://// ForFactorial - calculate factorial using the for
// construct.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int nNumberofArgs, char* pszArgs[])
{
// enter the number to calculate the factorial of
int nTarget;
cout << “This program calculates factorial.\n”
<< “Enter a number to take factorial of: “;
cin >> nTarget;
// start with an accumulator that’s initialized to 1
int nAccumulator = 1;
for(int nValue = 1; nValue <= nTarget; nValue++)
{
cout << nAccumulator << “ * “
<< nValue << “ equals “;
nAccumulator = nAccumulator * nValue;
cout << nAccumulator << endl;
}
// display the result
cout << nTarget << “ factorial is “
112 Part III: Becoming a Functional Programmer<< nAccumulator << endl;// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}The logic of this ForFactorial program is virtually identical to its olderFactorial twin: The program prompts the user to enter a number to take the
factorial of. It then initializes nAccumulator to 1 before entering the loopthat calculates the factorial.
ForFactorial creates an increment variable, nValue, that it initializes to 1in the setup clause of the for statement. That done, the program comparesnValue to nTarget, the value entered by the user in the test expressionsection of the for. If nValue is less than or equal to nTarget, control entersthe body of the loop where nAccumulator is multiplied by nValue.That done, control flows back up to the increment section of the for loop.This expression, nValue++, increments nValue by 1. Flow then moves tothe test expression, where nValue is compared with nTarget and theprocess repeated until eventually nValue exceeds the value of nTarget. Atthat point, control passes to the next statement after the closed brace.
The output from this program appears as follows:This program calculates factorials of user input.Enter a negative number to exit
Enter number: 5
5 factorial is 120
Enter number: 6
6 factorial is 720
Enter number: -1
Press any key to continue . . .All four sections of the for loop are optional. An empty setup, body, orincrement section has no effect; that is, it does nothing. (That makes sense.)An empty test expression is the same as true. (This is the only thing thatwould make sense — if it evaluated to false, then the body of the for loopwould never get executed, and the result would be useless.)
A variable defined within the setup section of a for loop is only defined withinthe for loop. It is no longer defined once control exits the loop.Chapter 10: Looping for the Fun of It 113
Getting More Done with
the Comma OperatorThere is a seemingly useless operator that I haven’t mentioned (up until now,that is) known as the comma operator. It appears as follows:expression1, expression2;This says execute expression1 and then execute expression2. The resultingvalue and type of the overall expression is the same as that of expression2.Thus, I could say something like the following:int i;int j;
i = 1, j = 2;Why would I ever want to do such a thing, you ask? Answer: You wouldn’texcept when writing for loops.The following CommaOperator program demonstrates the comma operator in
combat. This program calculates the products of pairs of numbers. If the operator enters N, the program outputs 1 * N, 2 * N-1, 3 * N-2, and so on, all the
way up to N * 1. (This program doesn’t do anything particularly useful. You’ll
see the comma operator used to effect when discussing arrays in Chapter 15.)//// CommaOperator - demonstrate how the comma operator
// is used within a for loop.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int nNumberofArgs, char* pszArgs[])
{
// enter a target number
int nTarget;
cout << “Enter maximum value: “;
cin >> nTarget;
114 Part III: Becoming a Functional Programmerfor(int nLower = 1, nUpper = nTarget;nLower <= nTarget; nLower++, nUpper--)
{
cout << nLower << “ * “
<< nUpper << “ equals “
<< nLower * nUpper << endl;
}
// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}The program first prompts the operator for a target value, which is read intonTarget. It then moves to the for loop. However, this time not only do youwant to increment a variable from 1 to nTarget, you also want to decrementa second variable from nTarget down to 1.Here the setup clause of the for loop declares a variable nLower that it initializes to 1 and a second variable nTarget that gets initialized to nTarget.The body of the loop displays nLower, nUpper, and the product nLower* nTarget. The increment section increments nLower and decrementsnUpper.The output from the program appears as follows:Enter maximum value: 151 * 15 equals 152 * 14 equals 28
3 * 13 equals 39
4 * 12 equals 48
5 * 11 equals 55
6 * 10 equals 60
7 * 9 equals 63
8 * 8 equals 64
9 * 7 equals 63
10 * 6 equals 60
11 * 5 equals 55
12 * 4 equals 48
13 * 3 equals 39
14 * 2 equals 28
15 * 1 equals 15
Press any key to continue . . .
Chapter 10: Looping for the Fun of It 115In this example run, I entered 15 as the target value. You can see how nLowerincrements in a straight line from 1 to 15, while nUpper makes its way from15 down to 1.
Actually, the output from this program is mildly interesting: No matter what
you enter, the value of the product increases rapidly at first as nLower increments from 1. Fairly quickly, however, the curve flattens out and asymptotically approaches the maximum value in the middle of the range beforeheading back down. The maximum value for the product always occurs whennLower and nUpper are equal.Could I have made the earlier for loop work without using the comma operator? Absolutely. I could have taken either variable, nLower or nUpper, out ofthe for loop and handled them as separate variables. Consider the followingcode snippet:nUpper = nTarget;for(int nLower = 1; nLower <= nTarget; nLower++)
{
cout << nLower << “ * “
<< nUpper << “ equals “
<< nLower * nUpper << endl;
nUpper--;
}This version would have worked just as well.The for loop can’t do anything that a while loop cannot do. In fact, any forloop can be converted into an equivalent while loop. However, because of itscompactness, you will see the for loop a lot more often.Up to and including this chapter, all of the programs have been one monolithic whole stretching from the opening brace after main() to the corresponding closing brace. This is okay for small programs, but it would bereally cool if you could divide your program into smaller bites that could be
digested separately. That is the goal of the next chapter on functions.
116 Part III: Becoming a Functional Programmer
No comments:
Post a Comment