Skip to content

5.4. Iterative Statements

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.

5.4.1. The while Statement

Fundamental

A whilestatement repeatedly executes a target statement as long as a condition is true. Its syntactic form is

c++
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.

INFO

Variables defined in a while condition or while body are created and destroyed on each iteration.

Using a while Loop

A 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:

INFO

Code for Exercise 5.13

(a)unsigned aCnt = 0, eCnt = 0, iouCnt = 0;

(b)unsigned index = some_value();

(c)unsigned evenCnt = 0, oddCnt = 0;

(d)unsigned ival=512, jval=1024, kval=4096;

c++
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.

INFO

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 is

how now now now brown cow cow

the output should indicate that the word now occurred three times.

5.4.2. Traditional for Statement

Fundamental

The syntactic form of the forstatement is:

c++
for (init-statement condition; expression)
    statement

The for and the part inside the parentheses is often referred to as the for header.

INFO

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

c++
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.

Execution Flow in a Traditional for Loop

Given the following for loop from § 3.2.3 (p. 94):

c++
// 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, index is defined and initialized to zero.

  2. Next, condition is evaluated. If index is not equal to s.size() and the character at s[index] is not whitespace, the for body is executed. Otherwise, the loop terminates. If the condition is false on the first iteration, then the for body is not executed at all.
  3. If the condition is true, the for body executes. In this case, the for body makes the character at s[index] uppercase.
  4. Finally, expression is evaluated. In this example, index is 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().

INFO

It is worth remembering that the visibility of any object defined within the for header is limited to the body of the for loop. Thus, in this example, index is inaccessible after the for completes.

Multiple Definitions in the for Header

As 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:

c++
// 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.

Omitting Parts of the for Header

A 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:

c++
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:

c++
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:

c++
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.

5.4.3. Range for Statement

Fundamental

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:

c++
for (declaration : expression)
    statement

C++11

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

INFO

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) { /*

(b)int ix;

(c)for (int ix = 0; ix != sz; ++ix, ++ sz) { /* . . . */ }

Exercise 5.16: The while loop is particularly good at executing while some condition holds; for example, when we need to read values until end-of-file. The for loop 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 of ints, write a program to determine whether one vector is a prefix of the other. For vectors of unequal length, compare the number of elements of the smaller vector. For example, given the vectors containing 0, 1, 1, and 2 and 0, 1, 1, 2, 3, 5, 8, respectively your program should return true.

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:

c++
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:

c++
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).

5.4.4. The do while Statement

A do whilestatement 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:

c++
do
        statement
while (condition);

INFO

A do while ends with a semicolon after the parenthesized 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:

c++
// 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:

c++
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!

INFO

Exercises Section 5.4.4

Exercise 5.18: Explain each of the following loops. Correct any problems you detect.

(a)do

(b)do {

(c)do {

Exercise 5.19: Write a program that uses a do while loop to repetitively request two strings from the user and report which string is less than the other.