for
LoopA for
loop provides a step-by-step recipe for performing repeated actions. Let’s take a more detailed look at how it’s set up. The usual parts of a for
loop handle these steps:
1. Setting a value initially
2. Performing a test to see whether the loop should continue
3. Executing the loop actions
4. Updating value(s) used for the test
The C++ loop design positions these elements so that you can spot them at a glance. The initialization, test, and update actions constitute a three-part control section enclosed in parentheses. Each part is an expression, and semicolons separate the expressions from each other. The statement following the control section is called the body of the loop, and it is executed as long as the test expression remains true:
for (initialization; test-expression; update-expression)
body
C++ syntax counts a complete for
statement as a single statement, even though it can incorporate one or more statements in the body portion. (Having more than one statement requires using a compound statement, or block, as discussed later in this chapter.)
The loop performs initialization just once. Typically, programs use this expression to set a variable to a starting value and then use the variable to count loop cycles.
test-expression
determines whether the loop body gets executed. Typically, this expression is a relational expression—that is, one that compares two values. Our example compares the value of i
to 5, checking whether i
is less than 5. If the comparison is true, the program executes the loop body. Actually, C++ doesn’t limit test-expression
to true/false comparisons. You can use any expression, and C++ will type cast it to type bool
. Thus, an expression with a value of 0 is converted to the bool
value false
, and the loop terminates. If the expression evaluates to nonzero, it is type cast to the bool
value true
, and the loop continues. Listing 5.2 demonstrates this by using the expression i
as the test condition. (In the update section, i--
is similar to i++
except that it decreases the value of i
by 1 each time it’s used.)
// num_test.cpp -- use numeric test in for loop
#include <iostream>
int main()
{
using namespace std;
cout << "Enter the starting countdown value: ";
int limit;
cin >> limit;
int i;
for (i = limit; i; i--) // quits when i is 0
cout << "i = " << i << "
";
cout << "Done now that i = " << i << "
";
return 0;
}
Here is the output from the program in Listing 5.2:
Enter the starting countdown value: 4
i = 4
i = 3
i = 2
i = 1
Done now that i = 0
Note that the loop terminates when i
reaches 0.
How do relational expressions, such as i < 5
, fit into this framework of terminating a loop with a 0 value? Before the bool
type was introduced, relational expressions evaluated to 1 if true and 0 if false. Thus, the value of the expression 3 < 5
was 1
, and the value of 5 < 5
was 0
. Now that C++ has added the bool
type, however, relational expressions evaluate to the bool
literals true
and false
instead of 1
and 0
. This change doesn’t lead to incompatibilities, however, because a C++ program converts true
and false
to 1
and 0
where integer values are expected, and it converts 0
to false
and nonzero to true
where bool
values are expected.
The for
loop is an entry-condition loop. This means the test expression is evaluated before each loop cycle. The loop never executes the loop body when the test expression is false. For example, suppose you rerun the program in Listing 5.2 but give 0 as a starting value. Because the test condition fails the very first time it’s evaluated, the loop body never gets executed:
Enter the starting countdown value: 0
Done now that i = 0
This look-before-you-loop attitude can help keep a program out of trouble.
update-expression
is evaluated at the end of the loop, after the body has been executed. Typically, it’s used to increase or decrease the value of the variable keeping track of the number of loop cycles. However, it can be any valid C++ expression, as can the other control expressions. This makes the for
loop capable of much more than simply counting from 0 to 5, the way the first loop example does. You’ll see some examples of this later.
The for
loop body consists of a single statement, but you’ll soon learn how to stretch that rule. Figure 5.1 summarizes the for
loop design.
A for
statement looks something like a function call because it uses a name followed by paired parentheses. However, for
’s status as a C++ keyword prevents the compiler from thinking for
is a function. It also prevents you from naming a function for
.
Common C++ style is to place a space between for
and the following parenthesis and to omit space between a function name and the following parenthesis:
for (i = 6; i < 10; i++)
smart_function(i);
Other control statements, such as if
and while
, are treated similarly to for
. This serves to visually reinforce the distinction between a control statement and a function call. Also common practice is to indent the body of a for
statement to make it stand out visually.
A for
control section uses three expressions. Within its self-imposed limits of syntax, C++ is a very expressive language. Any value or any valid combination of values and operators constitute an expression. For example, 10
is an expression with the value 10 (no surprise), and 28 * 20
is an expression with the value 560. In C++ every expression has a value. Often the value is obvious. For example, the following expression is formed from two values and the addition operator, and it has the value 49:
22 + 27
Sometimes the value is less obvious. For example, the following is an expression because it’s formed from two values and the assignment operator:
x = 20
C++ defines the value of an assignment expression to be the value of the member on the left, so the expression has the value 20. The fact that assignment expressions have values permits statements such as the following:
maids = (cooks = 4) + 3;
The expression cooks = 4
has the value 4, so maids
is assigned the value 7. However, just because C++ permits this behavior doesn’t mean you should encourage it. But the same rule that makes this peculiar statement possible also makes the following useful statement possible:
x = y = z = 0;
This is a fast way to set several variables to the same value. The precedence table (see Appendix D, “Operator Precedence”) reveals that assignment associates right-to-left, so first 0
is assigned to z
, and then z = 0
is assigned to y
, and so on.
Finally, as mentioned previously, relational expressions such as x < y
evaluate to the bool
values true
or false
. The short program in Listing 5.3 illustrates some points about expression values. The <<
operator has higher precedence than the operators used in the expressions, so the code uses parentheses to enforce the correct order.
// express.cpp -- values of expressions
#include <iostream>
int main()
{
using namespace std;
int x;
cout << "The expression x = 100 has the value ";
cout << (x = 100) << endl;
cout << "Now x = " << x << endl;
cout << "The expression x < 3 has the value ";
cout << (x < 3) << endl;
cout << "The expression x > 3 has the value ";
cout << (x > 3) << endl;
cout.setf(ios_base::boolalpha); //a newer C++ feature
cout << "The expression x < 3 has the value ";
cout << (x < 3) << endl;
cout << "The expression x > 3 has the value ";
cout << (x > 3) << endl;
return 0;
}
Here is the output from the program in Listing 5.3:
The expression x = 100 has the value 100
Now x = 100
The expression x < 3 has the value 0
The expression x > 3 has the value 1
The expression x < 3 has the value false
The expression x > 3 has the value true
Normally, cout
converts bool
values to int
before displaying them, but the cout.setf(ios::boolalpha)
function call sets a flag that instructs cout
to display the words true
and false
instead of 1
and 0
.
A C++ expression is a value or a combination of values and operators, and every C++ expression has a value.
To evaluate the expression x = 100
, C++ must assign the value 100
to x
. When the very act of evaluating an expression changes the value of data in memory, we say the evaluation has a side effect. Thus, evaluating an assignment expression has the side effect of changing the assignee’s value. You might think of assignment as the intended effect, but from the standpoint of how C++ is constructed, evaluating the expression is the primary effect. Not all expressions have side effects. For example, evaluating x + 15
calculates a new value, but it doesn’t change the value of x
. But evaluating ++x + 15
does have a side effect because it involves incrementing x
.
From expression to statement is a short step; you just add a semicolon. Thus, the following is an expression:
age = 100
Whereas the following is a statement:
age = 100;
More particularly, it is an expression statement. Any expression can become a statement if you add a semicolon, but the result might not make programming sense. For example, if rodents
is a variable, then the following is a valid C++ statement:
rodents + 6; // valid, but useless, statement
The compiler allows it, but the statement doesn’t accomplish anything useful. The program merely calculates the sum, does nothing with it, and goes on to the next statement. (A smart compiler might even skip the statement.)
Some concepts, such as knowing the structure of a for
loop, are crucial to understanding C++. But there are also relatively minor aspects of syntax that can suddenly bedevil you just when you think you understand the language. We’ll look at a couple of them now.
Although it is true that adding a semicolon to any expression makes it a statement, the reverse is not true. That is, removing a semicolon from a statement does not necessarily convert it to an expression. Of the kinds of statements we’ve used so far, return statements, declaration statements, and for
statements don’t fit the statement = expression + semicolon mold. For example, this is a statement:
int toad;
But the fragment int toad
is not an expression and does not have a value. This makes code such as the following invalid:
eggs = int toad * 1000; // invalid, not an expression
cin >> int toad; // can't combine declaration with cin
Similarly, you can’t assign a for
loop to a variable. In the following example, the for
loop is not an expression, so it has no value and you can’t assign it:
int fx = for (i = 0; i< 4; i++)
cout >> i; // not possible
C++ adds a feature to C loops that requires some artful adjustments to the for
loop syntax. This was the original syntax:
for (expression; expression; expression)
statement
In particular, the control section of a for
structure consisted of three expressions, as defined earlier in this chapter, separated by semicolons. C++ loops allow you do to things like the following, however:
for (int i = 0; i < 5; i++)
That is, you can declare a variable in the initialization area of a for
loop. This can be convenient, but it doesn’t fit the original syntax because a declaration is not an expression. This once outlaw behavior was originally accommodated by defining a new kind of expression, the declaration-statement expression, which was a declaration stripped of the semicolon, and which could appear only in a for
statement. That adjustment has been dropped, however. Instead, the syntax for the for
statement has been modified to the following:
for (for-init-statement condition; expression)
statement
At first glance, this looks odd because there is just one semicolon instead of two. But that’s okay because for-init-statement
is identified as a statement, and a statement has its own semicolon. As for for-init-statement
, it’s identified as either an expression-statement or a declaration. This syntax rule replaces an expression followed by a semicolon with a statement, which has its own semicolon. What this boils down to is that C++ programmers want to be able to declare and initialize a variable in a for
loop initialization, and they’ll do whatever is necessary to C++ syntax and to the English language to make it possible.
There’s a practical aspect to declaring a variable in for-init-statement
that you should know about. Such a variable exists only within the for
statement. That is, after the program leaves the loop, the variable is eliminated:
for (int i = 0; i < 5; i++)
cout << "C++ knows loops.
";
cout << i << endl; // oops! i no longer defined
Another thing you should know is that some older C++ implementations follow an earlier rule and treat the preceding loop as if i
were declared before the loop, thus making it available after the loop terminates.
3.145.107.100