7.4
The for Statement
Recall Listing 6.2 (iterativecounttofive.cpp). It simply counts from one to five. Counting is a frequent activity performed by computer programs. Certain program elements are required in order for any program to count:
• A variable must be used to keep track of the count; in Listing 6.2 (iterativecounttofive.cpp), count is the aptly named counter variable.
• The counter variable must be given an initial value. In the case of Listing 6.2 (iterativecounttofive.cpp), the initial value is 1.
• The variable must be modified (usually incremented) as the program counts. The statement
count++;
increments count in Listing 6.2 (iterativecounttofive.cpp).
• A way must be provided to determine if the counting has completed. In Listing 6.2 (iterativecounttofive.cpp), the condition of thewhilestatement determines if the counting is complete or must contine.
C++provides a specialized loop that packages these four programming elements into one convenient statement. Called theforstatement, its general form is
for
(initialization ; condition ; modification )
statement;
• The reserved wordforidentifies aforstatement.
• The loop is controlled by a special variable called the loop variable.
• The header, contained in parentheses, contains three parts, each separated by semicolons:
– Initialization. The initialization part assigns an initial value to the loop variable. The loop variable may be declared here as well; if it is declared here, then its scope is limited to thefor statement. This means you may use that loop variable only within the loop. It also means you are free to reuse that variable’s name outside the loop to declare a different variable with the same name as the loop variable.
The initialization part is performed one time.
– Condition. The condition part is a Boolean expression, just like the condition of awhile statement. The condition is checked each time before the body is executed.
– Modification. The modification part generally changes the loop variable. The change should be such that the condition will eventually become false so the loop will terminate. The modification is performed during each iteration after the body is executed.
Notice that the last part (modification) is not following by a semicolon; semicolons are used strictly to separate the three parts.
• The statement is like the body of any other loop. It may be a compound statement within curly braces. Anyforloop can be rewritten as awhileloop. The general form of theforloop given above can be written equivalently as
7.4. THE FOR STATEMENT 156
initialization;
while
(
condition )
{
statement;
modification;
}
Listing 7.4 (forcounttofive.cpp) uses aforstatement to count to five.
Listing 7.4: forcounttofive.cpp 1 #include <iostream> 2 3 using namespace std; 4 5 int main() 6 {
7 for ( int count = 1; count <= 5; count++ ) 8 cout << count << endl; // Display counter
9 }
With awhileloop, the four counting components (variable declaration, initialization, condition, and modification can be scattered throughout the code. With a forloop, a programmer should be able to determine all the important information about the loop’s control by looking at one statement.
Recall Listing 6.12 (timestable.cpp) that prints a multiplication table on the screen. We can organize its code better by converting all thewhilestatements toforstatements. The result uses far less code, as shown in Listing 7.5 (bettertimestable.cpp).
Listing 7.5: bettertimestable.cpp 1 #include <iostream> 2 #include <iomanip> 3 4 using namespace std; 5 6 int main() 7 {
8 int size; // The number of rows and columns in the table
9 cout << "Please enter the table size: "; 10 cin >> size;
11 // Print a size x size multiplication table
12
13 // First, print heading
14 cout << " ";
15 for ( int column = 1; column <= size; column++ )
16 cout << setw(4) << column; // Print heading for this column.
17 cout << endl;
18 // Print line separator
19 cout << " +";
20 for ( int column = 1; column <= size; column++ )
7.4. THE FOR STATEMENT 157
22 cout << endl;
23 // Print table contents
24 for ( int row = 1; row <= size; row++ )
25 {
26 cout << setw(4) << row << " |"; // Print row label.
27 for ( int column = 1; column <= size; column++ )
28 cout << setw(4) << row*column; // Display product
29 cout << endl; // Move cursor to next row
30 }
31 }
Aforloop is ideal for stepping through the rows and columns. The information about the control of both loops is now packaged in the respectiveforstatements instead of being spread out in various places in main. In thewhileversion, it is easy for the programmer to forget to update one or both of the counter variables (row and/or column). Theformakes it harder for the programmer to forget the loop variable update, since it is done right up front in theforstatement header.
It is considered bad programming practice to do either of the following in aforstatement:
• Modify the loop control variable within the body of the loop—if the loop variable is modified within the body, then the logic of the loop’s control is no longer completely isolated to theforstate- ment’s header. The programmer must look elsewhere within the statement to understand completely how the loop works.
• Prematurely exit the loop with abreak—this action also violates the concept of keeping all the loop control logic in one place (thefor’s header).
The language allows both of these practices, but experience shows that it is best to avoid them. If it seems necessary to violate this advice, consider using a different kind of loop. Thewhileanddo/whileloops do not imply the same degree of control regularity expected in aforloop.
Listing 7.6 (permuteabcd.cpp) is a rewrite of Listing 6.13 (permuteabc.cpp) that replaces itswhile loops withforloops and adds an additional character.
Listing 7.6: permuteabcd.cpp 1 // File permuteabcd.cpp 2 3 #include <iostream> 4 5 using namespace std; 6 7 int main() 8 {
9 for ( char first = 'A'; first <= 'D'; first ++ ) 10 for ( char second = 'A'; second <= 'D'; second++ ) 11 if ( second != first ) // No duplicate letters
12 for ( char third = 'A'; third <= 'D'; third++ ) 13 if ( third != first && third != second )
14 for ( char fourth = 'A'; fourth <= 'D'; fourth++ )
15 if ( fourth != first && fourth != second && fourth != third ) 16 cout << first << second << third << fourth << endl;
7.4. THE FOR STATEMENT 158
Notice that since all the variable initialization and incrementing is taken care of in theforstatement headers, we no longer need compound statements in the loop bodies, so the curly braces are unnecessary. Listing 7.6 (permuteabcd.cpp) prints all 24 permutations of ABCD:
ABCD ABDC ACBD ACDB ADBC ADCB BACD BADC BCAD BCDA BDAC BDCA CABD CADB CBAD CBDA CDAB CDBA DABC DACB DBAC DBCA DCAB DCBA
Listing 7.7 (forprintprimes.cpp) is a rewrite of Listing 6.21 (printprimes.cpp) that replaces itswhile loops withforloops.
Listing 7.7: forprintprimes.cpp 1 #include <iostream> 2 3 using namespace std; 4 5 int main() 6 { 7 8 int max_value;
9 cout << "Display primes up to what value? "; 10 cin >> max_value;
11 for ( int value = 2; value <= max_value; value++ )
12 {
13 // See if value is prime
14 bool is_prime = true; // Provisionally, value is prime
15 // Try all possible factors from 2 to value - 1
7.4. THE FOR STATEMENT 159
17 is_prime && trial_factor < value;
18 trial_factor++ )
19 is_prime = (value % trial_factor != 0 );
20 if ( is_prime )
21 cout << value << " "; // Display the prime number
22 }
23 cout << endl; // Move cursor down to next line
24 }
As shown in Listing 7.7 (forprintprimes.cpp), the conditional expression in theforloop is not limited to a simple test of the loop control variable; it can be any legal Boolean expression. The logical and (&&), or (||), and not (!) operators can be used to create complex Boolean expressions, if necessary. The modification part of theforloop is not limited to simple arithmetic and can be quite elaborate. For example:
for ( double d = 1000; d >= 1; cin >> d ) {
/* Body goes here */ }
Here d is reassigned from the input stream. If necessary, multiple variables can be initialized in the initial- ization part:
for ( int i = 0, j = 100; i < j; i++ ) {
/* Body goes here */ }
While theforstatement supports such complex headers, simpler is usually better. Ordinarily thefor loop should manage just one control variable, and the initialization, condition, and modification parts should be straightforward. If a particular programming situation warrants an overly complicatedforconstruction, consider using another kind of loop.
Any or all of the parts of theforstatement (initialization, condition, modification, and body) may be omitted:
• Initialization. If the initialization is missing, as in for (; i < 10; i++ )
/* Body goes here */
then no initialization is performed by theforloop, and it must be done elsewhere. • Condition. If the condition is missing, as in
for ( int i = 0; ; i++ ) /* Body goes here */
then the condition is true by default. Abreakorgotomust appear in the body unless an infinite loop is intended.
• Modification. If the modification is missing, as in for ( int i = 0; i < 10; )
7.4. THE FOR STATEMENT 160
then theforperforms no automatic modification; the modification must be done by a statement in the body to avoid an infinite loop.
• Body. If the body is missing, as in
for ( int i = 0; i < 10; i++ ) {}
or
for ( int i = 0; i < 10; i++ );
then an empty loop results. This can be used for a non-portable delay (slower computers will delay longer than faster computers), but some compilers may detect that such code has no functional effect and optimize away such an empty loop. This means the compiler will ignore theforaltogether.
As mentioned in Section 5.3, be careful about accidentally putting a semicolon at the end of theforheader, as in
for ( int i = 0; i < 10; i++ ); /* Intended body goes here */
The semicolon terminates theforstatement, and the intended body that follows is not the body, even though it may be properly indented.
One common C/C++idiom to make an intentional infinite loop is to use aforstatement with all control information missing:
for ( ;; )
/* Body goes here */
Omitting all the parts of theforheader is a statement from the programmer that says “I know what I am doing—I really want an infinite loop here.” Of course, it actually may not be infinite because the body may contain abreakorgotostatement.
While theforstatement supports the omission of parts of its header, such constructs should be avoided. The intention of theforloop is to allow the programmer to see all the aspects of the loop’s control in one place. If some of these control responsibilities are to be handled elsewhere (not in thefor’s header) then consider using another kind of loop.
Programmers usually select a simple name for the control variable of afor statement. Recall that variable names should be well chosen to reflect the meaning of their use within the program. It may come as a surprise that i is probably the most common name used for an integer control variable in aforloop. This practice has its roots in mathematics where variables such as i, j, and k are commonly used to index vectors and matrices. Such mathematical structures have programming analogs in arrays (chrefch:arrays) and vectors (Section 13.2). Computer programmers make considerable use offorloops in array and vector processing, so programmers have universally adopted this convention of short control variable names. Thus, it generally is acceptable to use simple identifiers like i as loop control variables.
C++allows thebreak,continue, andgotostatements to be used in the body of aforstatement. Like with thewhileanddo/whilestatements,breakcauses immediate loop termination,continue causes the condition to be immediately checked to determine if the iteration should continue, andgoto jumps to a label somewhere in the function. As previously mentioned, however,forloop control should be restricted to its header, and the use ofbreak,continue, andgotowithinforloops should be avoided.
7.5. SUMMARY 161
Anyforloop can be rewritten with awhileloop and behave identically. For example, consider the forloop
for ( int i = 1; i <= 10; i++ ) cout << i << endl;
and next consider thewhileloop that behaves exactly the same way: int i = 1; while ( i <= 10 ) { cout << i << endl; i++; }
Which is better? Theforloop conveniently packages the loop control information in its header, but in thewhileloop this information is distributed throughout the small section of code. The forloop thus provides a better organization of the loop control code. Does one loop outperform the other? No, most compilers produce essentially the same code for both constructs. Thus, theforloop is preferred in this example.
7.5
Summary
• Theswitchstatement is an alternative to some multi-wayif/elsestatements. • Not all multi-wayif/elsestatements can be converted directly to aswitchstatement.
• The expression to evaluate within theswitchstatement must evaluate to an integral value (int, short,long,char, orbool).
• Thecaselabels within a switchstatement must be integral literalsliterals or constants (int, short,long,char, orbool). Specifically,caselabels may not be variables or other expres- sions.
• Program execution jumps to thecaselabel with the value that matches theswitchexpression. • Once acaselabel is matched, program execution continues within theswitchstatement until a
breakstatement is encountered.
• If nocaselabels match theswitchexpression, the program execution jumps to thedefault label, if it is present. If nocase labels match and nodefaultlabel is present, no part of the switchbody is executed.
• The conditional operator is an expression that evaluates to one of two values depending on a given condition.
• Thedo/whileis a bottom-checking loop, unlike thewhileloop, which is a top-checking loop. • The body of ado/whileloop is always executed at least once, regardless of the condition. The
body of awhileloop is not executed if the condition is initiallyfalse.
• Theforloop is a top-checking loop that, when used properly, concentrates all the information about its control in one convenient location.
7.6. EXERCISES 162
• The three parts of theforloop control are initialization, condition, and modification.
• Theforstatement is best used for a loop that can be controlled by a single variable with a definite starting value, a definite ending value, and a regular way to update the variable’s value.
• Aforloop is ideal for counting.
• Any or all of the three parts in theforloop header can be omitted; however, if you feel the need to omit one or more of the parts, thewhilestatement may be a better choice.
• Best practice avoids modifying the control variable of aforstatement within the loop’s body; the modification should be limited to the third part of theforheader.
• The <iomanip> library provides the setw object that provides special formatting for output sent to cout.
7.6
Exercises
1. Consider the following code fragment. int x; cin >> x; switch ( x + 3 ) { case 5: cout << x << endl; break; case 10: cout << x - 3 << endl; break; case 20: cout << x + 3 << endl; break; }
(a) What is printed when the user enters 2? (b) What is printed when the user enters 5? (c) What is printed when the user enters 7? (d) What is printed when the user enters 17? (e) What is printed when the user enters 20? (f) What is printed when the user enters 5? 2. Consider the following code fragment.
char ch; cin >> ch; switch ( ch ) { case 'a': cout << "*" << endl;
7.6. EXERCISES 163 break; case 'A': cout << "**" << endl; break; case 'B': case 'b': cout << "***" << endl; case 'C': case 'c': cout << "****" << endl; break; default: cout << "*****" << endl; }
(a) What is printed when the user enters a? (b) What is printed when the user enters A? (c) What is printed when the user enters b? (d) What is printed when the user enters B? (e) What is printed when the user enters C? (f) What is printed when the user enters c? (g) What is printed when the user enters t? 3. What is printed by the following code fragment?
int x = 0; do { cout << x << " "; x++; } while ( x < 10 ); cout << endl;
4. What is printed by the following code fragment? int x = 20; do { cout << x << " "; x++; } while ( x < 10 ); cout << endl;
5. What is printed by the following code fragment? for ( int x = 0; x < 10; x++ )
cout << "*"; cout << endl;
7.6. EXERCISES 164 int value; char ch; cin >> ch; if ( ch == 'A' ) value = 10; else if ( ch == 'P' ) value = 20; else if ( ch == 'T' ) value = 30; else if ( ch == 'V' ) value = 40; else value = 50;
cout << value << endl;
7. Rewrite the following code fragment so that a multi-wayif/elseis used instead of theswitch statement. int value; char ch; cin >> ch; switch( ch ) { case 'A': value = 10; break; case 'P': cin >> value; break; case 'T': value = ch; break; case 'V': value = ch + 1000; break; default: value = 50; }
cout << value << endl;
8. Rewrite the following code fragment so that a multi-wayif/elseis used instead of theswitch statement. int value; char ch; cin >> ch; switch( ch ) { case 'A': cout << ch << endl; value = 10;
7.6. EXERCISES 165 break; case 'P': case 'E': cin >> value; break; case 'T': cin >> ch; value = ch; case 'C': value = ch;
cout << "value=" << value << ", ch=" << ch << endl;
break;
case 'V':
value = ch + 1000;
break; }
cout << value << endl;
9. Rewrite the following code fragment so awhileloop is used instead of theforstatement. for ( int i = 100; i > 0; i-- )
cout << i << endl;
10. Rewrite the following code fragment so that it uses the conditional operator instead of anifstate- ment:
if ( value % 2 != 0 ) // Is value even?
value = value + 1; // If not, make it even.
11. Rewrite the following code fragment so that it uses the conditional operator instead of anif/else statement:
if ( value % 2 == 0 ) // Is value even?
value = 0; // If so, make it zero.
else
value = value + 1; // Otherwise, make it even.
12. Would the following multi-wayif/elsebe a good candidate to rewrite as aswitchstatement? If so, rewrite the code using aswitch; otherwise, explain why it is impractical to do so.
int x, y; cin >> x >> y; if ( x < 10 ) y = 10; else if ( x == 5 ) y = 5; else if ( x == y ) y = 0; else if ( y > 10 ) x = 10; else x = y;
167
Chapter 8
Using Functions
Suppose you must write a C++program that computes the square root of a number supplied by the user. Listing 8.1 (computesquareroot.cpp) provides a simple implementation.
Listing 8.1: computesquareroot.cpp 1 // File squareroot.cpp 2 3 #include <iostream> 4 5 using namespace std; 6 7 int main() 8 { 9 double input; 10
11 // Get value from the user
12 cout << "Enter number: "; 13 cin >> input;
14 double diff;
15 // Compute a provisional square root
16 double root = 1.0; 17
18 do // Loop until the provisional root
19 { // is close enough to the actual root
20 root = (root + input/root) / 2.0; 21 cout << "root is " << root << endl; 22 // How bad is the approximation?
23 diff = root * root - input;
24 }
25 while (diff > 0.0001 || diff < -0.0001); 26
27 // Report approximate square root
28 cout << "Square root of " << input << " = " << root << endl;
29 }
The program is based on a simple algorithm that uses successive approximations to zero in on an answer that is within 0.00000001 of the true answer.
8.1. INTRODUCTION TO USING FUNCTIONS 168
One sample run is
Enter number: 2 root is 1.5 root is 1.41667 root is 1.41422
Square root of 2 = 1.41422
The actual square root is approximately 1.4142135623730951 and so the result is within our accepted tolerance (0.0001). Another run is
Enter number: 100 root is 50.5 root is 26.2401 root is 15.0255 root is 10.8404 root is 10.0326 root is 10.0001 root is 10 Square root of 100 = 10
which is, of course, the exact answer.
While this code may be acceptable for many applications, better algorithms exist that work faster and produce more precise answers. Another problem with this code is, what if you are working on a significant scientific or engineering application and must compute square roots in various places throughout the source