Iterative statements, commonly called loops, provide for repeated execution until a condition is true. The while and for statements test the condition before executing the body. The do while executes the body and then tests its condition.
while Statement
A while
statement repeatedly executes a target statement as long as a condition is true. Its syntactic form is
while (condition)
statement
In a while, statement (which is often a block) is executed as long as condition evaluates as true. condition may not be empty. If the first evaluation of condition yields false, statement is not executed.
The condition can be an expression or an initialized variable declaration (§ 5.2, p. 174). Ordinarily, the condition itself or the loop body must do something to change the value of the expression. Otherwise, the loop might never terminate.
Variables defined in a
whilecondition orwhilebody are created and destroyed on each iteration.
while LoopA while loop is generally used when we want to iterate indefinitely, such as when we read input. A while is also useful when we want access to the value of the loop control variable after the loop finishes. For example:
(a)
unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
char ch = next_text();
switch (ch) {
case 'a': aCnt++;
case 'e': eCnt++;
default: iouCnt++;
}(b)
unsigned index = some_value();
switch (index) {
case 1:
int ix = get_value();
ivec[ ix ] = index;
break;
default:
ix = ivec.size()-1;
ivec[ ix ] = index;
}(c)
unsigned evenCnt = 0, oddCnt = 0;
int digit = get_num() % 10;
switch (digit) {
case 1, 3, 5, 7, 9:
oddcnt++;
break;
case 2, 4, 6, 8, 10:
evencnt++;
break;
}(d)
unsigned ival=512, jval=1024, kval=4096;
unsigned bufsize;
unsigned swt = get_bufCnt();
switch(swt) {
case ival:
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
vector<int> v;
int i;
// read until end-of-file or other input failure
while (cin >> i)
v.push_back(i);
// find the first negative element
auto beg = v.begin();
while (beg != v.end() && *beg >= 0)
++beg;
if (beg == v.end())
// we know that all elements in v are greater than or equal to zero
The first loop reads data from the standard input. We have no idea how many times this loop will execute. The condition fails when cin reads invalid data, encounters some other input failure, or hits end-of-file. The second loop continues until we find a negative value. When the loop terminates, beg is either equal to v.end(), or it denotes an element in v whose value is less than zero. We can use the state of beg outside the while to determine further processing.
Exercises Section 5.4.1
Exercise 5.14: Write a program to read
strings from standard input looking for duplicated words. The program should find places in the input where one word is followed immediately by itself. Keep track of the largest number of times a single repetition occurs and which word is repeated. Print the maximum number of duplicates, or else print a message saying that no word was repeated. For example, if the input ishow now now now brown cow cow
the output should indicate that the word
nowoccurred three times.
for Statement
The syntactic form of the for
statement is:
for (init-statement condition; expression)
statement
The for and the part inside the parentheses is often referred to as the for header.
init-statement must be a declaration statement, an expression statement, or a null statement. Each of these statements ends with a semicolon, so the syntactic form can also be thought of as
for (initializer; condition; expression)
statement
In general, init-statement is used to initialize or assign a starting value that is modified over the course of the loop. condition serves as the loop control. As long as condition evaluates as true, statement is executed. If the first evaluation of condition yields false, statement is not executed. expression usually modifies the variable(s) initialized in init-statement and tested in condition. expression is evaluated after each iteration of the loop. As usual, statement can be either a single or a compound statement.
for LoopGiven the following for loop from § 3.2.3 (p. 94):
// process characters in s until we run out of characters or we hit a whitespace
for (decltype(s.size()) index = 0;
index != s.size() && !isspace(s[index]); ++index)
s[index] = toupper(s[index]); // capitalize the current character
the order of evaluation is as follows:
1. init-statement is executed once at the start of the loop. In this example,
indexis defined and initialized to zero.
2. Next, condition is evaluated. If
indexis not equal tos.size()and the character ats[index]is not whitespace, theforbody is executed. Otherwise, the loop terminates. If the condition isfalseon the first iteration, then theforbody is not executed at all.
3. If the condition is
true, theforbody executes. In this case, theforbody makes the character ats[index]uppercase.
4. Finally, expression is evaluated. In this example,
indexis incremented by 1.
These four steps represent the first iteration of the for loop. Step 1 is executed only once on entry to the loop. Steps 2, 3, and 4 are repeated until the condition evaluates as false—that is, when we encounter a whitespace character in s, or index is greater than s.size().
It is worth remembering that the visibility of any object defined within the
forheader is limited to the body of theforloop. Thus, in this example,indexis inaccessible after theforcompletes.
for HeaderAs in any other declaration, init-statement can define several objects. However, init-statement may be only a single declaration statement. Therefore, all the variables must have the same base type (§ 2.3, p. 50). As one example, we might write a loop to duplicate the elements of a vector on the end as follows:
// remember the size of v and stop when we get to the original last element
for (decltype(v.size()) i = 0, sz = v.size(); i != sz; ++i)
v.push_back(v[i]);
In this loop we define both the index, i, and the loop control, sz, in init-statement.
for HeaderA for header can omit any (or all) of init-statement, condition, or expression.
We can use a null statement for init-statement when an initialization is unnecessary. For example, we might rewrite the loop that looked for the first negative number in a vector so that it uses a for:
auto beg = v.begin();
for ( /* null */; beg != v.end() && *beg >= 0; ++beg)
; // no work to do
Note that the semicolon is necessary to indicate the absence of init-statement—more precisely, the semicolon represents a null init-statement. In this loop, the for body is also empty because all the work of the loop is done inside the for condition and expression. The condition decides when it’s time to stop looking and the expression increments the iterator.
Omitting condition is equivalent to writing true as the condition. Because the condition always evaluates as true, the for body must contain a statement that exits the loop. Otherwise the loop will execute indefinitely:
for (int i = 0; /* no condition */ ; ++i) {
// process i; code inside the loop must stop the iteration!
}
We can also omit expression from the for header. In such loops, either the condition or the body must do something to advance the iteration. As an example, we’ll rewrite the while loop that read input into a vector of ints:
vector<int> v;
for (int i; cin >> i; /* no expression */ )
v.push_back(i);
In this loop there is no need for an expression because the condition changes the value of i. The condition tests the input stream so that the loop ends when we’ve read all the input or encounter an input error.
for Statement
The new standard introduced a simpler for statement that can be used to iterate through the elements of a container or other sequence. The syntactic form of the range for statement is:
for (declaration : expression)
statement
expression must represent a sequence, such as a braced initializer list (§ 3.3.1, p. 98), an array (§ 3.5, p. 113), or an object of a type such as vector or string that has begin and end members that return iterators (§ 3.4, p. 106).
declaration defines a variable. It must be possible to convert each element of the sequence to the variable’s type (§ 4.11, p. 159). The easiest way to ensure that the
Exercises Section 5.4.2
Exercise 5.15: Explain each of the following loops. Correct any problems you detect.
(a)
for (int ix = 0; ix != sz; ++ix) { /* . . . */ }
if (ix != sz)
// . . .(b)
int ix;
for (ix != sz; ++ix) { /* . . . */ }(c)
for (int ix = 0; ix != sz; ++ix, ++ sz) { /*. . .*/ }Exercise 5.16: The
whileloop is particularly good at executing while some condition holds; for example, when we need to read values until end-of-file. Theforloop is generally thought of as a step loop: An index steps through a range of values in a collection. Write an idiomatic use of each loop and then rewrite each using the other loop construct. If you could use only one loop, which would you choose? Why?Exercise 5.17: Given two
vectors ofints, write a program to determine whether onevectoris a prefix of the other. Forvectors of unequal length, compare the number of elements of the smallervector. For example, given thevectors containing0,1,1, and2and0,1,1,2,3,5,8, respectively your program should returntrue.
types match is to use the auto type specifier (§ 2.5.2, p. 68). That way the compiler will deduce the type for us. If we want to write to the elements in the sequence, the loop variable must be a reference type.
On each iteration, the control variable is defined and initialized by the next value in the sequence, after which statement is executed. As usual, statement can be a single statement or a block. Execution ends once all the elements have been processed.
We have already seen several such loops, but for completeness, here is one that doubles the value of each element in a vector:
vector<int> v = {0,1,2,3,4,5,6,7,8,9};
// range variable must be a reference so we can write to the elements
for (auto &r : v) // for each element in v
r *= 2; // double the value of each element in v
The for header declares the loop control variable, r, and associates it with v. We use auto to let the compiler infer the correct type for r. Because we want to change the value of the elements in v, we declare r as a reference. When we assign to r inside the loop, that assignment changes the element to which r is bound.
A range for is defined in terms of the equivalent traditional for:
for (auto beg = v.begin(), end = v.end(); beg != end; ++beg) {
auto &r = *beg; // r must be a reference so we can change the element
r *= 2; // double the value of each element in v
}
Now that we know how a range for works, we can understand why we said in § 3.3.2 (p. 101) that we cannot use a range for to add elements to a vector (or other container). In a range for, the value of end() is cached. If we add elements to (or remove them from) the sequence, the value of end might be invalidated (§ 3.4.1, p. 110). We’ll have more to say about these matters in § 9.3.6 (p. 353).
do while StatementA do while
statement is like a while but the condition is tested after the statement body completes. Regardless of the value of the condition, we execute the loop at least once. The syntactic form is as follows:
do
statement
while (condition);
In a do, statement is executed before condition is evaluated. condition cannot be empty. If condition evaluates as false, then the loop terminates; otherwise, the loop is repeated. Variables used in condition must be defined outside the body of the do while statement.
We can write a program that (indefinitely) does sums using a do while:
// repeatedly ask the user for a pair of numbers to sum
string rsp; // used in the condition; can't be defined inside the do
do {
cout << "please enter two values: ";
int val1 = 0, val2 = 0;
cin >> val1 >> val2;
cout << "The sum of " << val1 << " and " << val2
<< " = " << val1 + val2 << "\n\n"
<< "More? Enter yes or no: ";
cin >> rsp;
} while (!rsp.empty() && rsp[0] != 'n');
The loop starts by prompting the user for two numbers. It then prints their sum and asks whether the user wishes to do another sum. The condition checks that the user gave a response. If not, or if the input starts with an n, the loop is exited. Otherwise the loop is repeated.
Because the condition is not evaluated until after the statement or block is executed, the do while loop does not allow variable definitions inside the condition:
do {
// . . .
mumble(foo);
} while (int foo = get_foo()); // error: declaration in a do condition
If we could define variables in the condition, then any use of the variable would happen before the variable was defined!
Exercises Section 5.4.4
Exercise 5.18: Explain each of the following loops. Correct any problems you detect.
(a)
do
int v1, v2;
cout << "Please enter two numbers to sum:" ;
if (cin >> v1 >> v2)
cout << "Sum is: " << v1 + v2 << endl;
while (cin);(b)
do {
// . . .
} while (int ival = get_response());(c)
do {
int ival = get_response();
} while (ival);Exercise 5.19: Write a program that uses a
do whileloop to repetitively request twostrings from the user and report whichstringis less than the other.