On this page

Loops

So far every statement you wrote ran once, or not at all. A loop runs the same statements many times. This lesson shows the three loops of C++, how to count the number of times each one runs, and how to follow a loop on paper, one row of a table at a time.

The same statement, many times

This program draws five circles in a row.

#include "scimigo.h"
using namespace scimigo;

int main() {
    canvas(600, 400);
    circle(100, 200, 30, "teal");
    circle(200, 200, 30, "teal");
    circle(300, 200, 30, "teal");
    circle(400, 200, 30, "teal");
    circle(500, 200, 30, "teal");
}

The five statements differ in one value only: x is 100, then 200, 300, 400, 500. Each x is 100 more than the one before.

Writing them out works for five circles. It does not work for five hundred, and it does not work when the number of circles is known only while the program runs.

Put x in a variable, and the difference between the statements disappears.

int x = 100;
circle(x, 200, 30, "teal");
x = x + 100;
circle(x, 200, 30, "teal");
x = x + 100;

Now the same two statements come again and again: draw a circle at x, then add 100 to x. Statements that repeat exactly are what a loop is for. You write them once and say how long to keep going.

while

The first loop is while. It looks like an if, and it starts like one.

#include <iostream>

int main() {
    int n = 3;
    while (n > 0) {
        std::cout << n << "\n";
        n = n - 1;
    }
    std::cout << "Lift off\n";
}
3
2
1
Lift off

The statements between the braces are the loop's body. This is what the computer does:

  1. It works out the condition n > 0. This is the test.
  2. If the test is true, it runs the whole body, and then goes back to step 1.
  3. If the test is false, it skips the body and carries on after the closing brace.

An if does steps 1 and 3 and never goes back. Going back is the only difference.

Each run of the body is one turn of the loop. To follow a loop on paper, write a table with one row for each time the test is worked out.

Test number n n > 0 Printed n after the body
1 3 true 3 2
2 2 true 2 1
3 1 true 1 0
4 0 false nothing the loop is over

Notice two things.

  • The test is worked out four times, and the body runs three times. The last test is the one that comes out false.
  • The test is looked at only at the top. When n becomes 0 in the middle of the third turn, nothing happens yet. The loop ends when the computer goes back to the test and finds it false.

Here are the five circles again, drawn by a loop.

#include "scimigo.h"
using namespace scimigo;

int main() {
    canvas(600, 400);
    int x = 100;
    while (x <= 500) {
        circle(x, 200, 30, "teal");
        x = x + 100;
    }
}

There is one circle statement, and it runs five times, with x equal to 100, 200, 300, 400 and 500. Then x becomes 600, the test x <= 500 is false, and the loop is over.

Start, test, update

A loop that counts has three parts, and each one is a place where it can go wrong.

#include <iostream>

int main() {
    int count = 0;              // the start value
    while (count < 3) {         // the test
        std::cout << "knock\n";
        count = count + 1;      // the update
    }
    std::cout << count << "\n";
}
knock
knock
knock
3
  • The start value is given once, before the loop.
  • The test is worked out before every turn.
  • The update changes the variable, so that the test will one day be false.

The last line prints 3. After a loop, its test is false: here count < 3 is false, because count is 3.

Now think about this program without its update line. count would stay 0, the test 0 < 3 would be true every time, and the program would print knock without end. A loop whose test never becomes false is an infinite loop. The compiler does not notice it, because every statement is correct C++. The lab stops a program that runs for too long and tells you so. When you see that message, look for the update first.

Shorter spellings

Changing a variable by a fixed amount is so common that C++ has shorter ways to write it.

Long form Shorter Shortest
i = i + 1; i += 1; ++i;
i = i - 1; i -= 1; --i;
i = i + 5; i += 5;
total = total + price; total += price;

Each row is one meaning written in different ways: read the variable, work out the new value, store it back.

#include <iostream>

int main() {
    int i = 10;
    ++i;
    std::cout << i << "\n";
    i += 5;
    std::cout << i << "\n";
    i -= 6;
    std::cout << i << "\n";
    --i;
    std::cout << i << "\n";
}
11
16
10
9

You will also see i++. As a statement of its own it does the same as ++i. This course writes ++i.

for

The three parts of a counting loop are easy to lose: the start value sits above the loop and the update is at the bottom of the body. A for loop puts all three on one line.

This program has the same loop twice, first as a while and then as a for.

#include <iostream>

int main() {
    int i = 1;
    while (i <= 3) {
        std::cout << "Lap " << i << "\n";
        ++i;
    }

    for (int k = 1; k <= 3; ++k) {
        std::cout << "Lap " << k << "\n";
    }
}
Lap 1
Lap 2
Lap 3
Lap 1
Lap 2
Lap 3

Inside the parentheses of a for are three parts, separated by two semicolons.

Part In this loop When it runs
start int k = 1 once, before anything else
test k <= 3 before every turn
update ++k after every turn of the body

The update is written on the first line, but it runs after the body, exactly where ++i; stands in the while loop. Here is the for loop traced by hand.

Turn k k <= 3 Printed k after the update
1 1 true Lap 1 2
2 2 true Lap 2 3
3 3 true Lap 3 4
4 false nothing the loop is over

A variable declared in the parentheses of a for belongs to that loop. It ends at the loop's closing brace, by the rule you know from module 4. This program does not compile, because its last statement uses k after the loop.

#include <iostream>

int main() {
    for (int k = 1; k <= 3; ++k) {
        std::cout << "Lap " << k << "\n";
    }
    std::cout << k << "\n";
}

Using the counter

The counter is an ordinary variable, and the body can calculate with it. That is how one statement draws different things on different turns.

#include "scimigo.h"
using namespace scimigo;

int main() {
    canvas(600, 400);
    for (int i = 0; i < 6; ++i) {
        rectangle(40 + i * 90, 170, 60, 60, "teal");
    }
}
i 40 + i * 90
0 40
1 130
2 220
5 490

The first square is at the start position, 40, because i starts at 0 and 0 * 90 is 0. Each turn moves the next square 90 to the right.

Use for when you can say the start, the test and the update in one breath: "for i from 0 up to 6". Use while when you cannot.

Ten or eleven?

How many turns does a loop make? The answer is in the start value and the test, and one character changes it.

#include <iostream>

int main() {
    int turns = 0;
    for (int i = 0; i < 5; ++i) {
        ++turns;
    }
    std::cout << turns << "\n";

    turns = 0;
    for (int i = 0; i <= 5; ++i) {
        ++turns;
    }
    std::cout << turns << "\n";

    turns = 0;
    for (int i = 1; i <= 5; ++i) {
        ++turns;
    }
    std::cout << turns << "\n";
}
5
6
5

To count the turns of any loop, write down the values the counter takes.

Loop Values of i in the body Turns
for (int i = 0; i < 5; ++i) 0, 1, 2, 3, 4 5
for (int i = 0; i <= 5; ++i) 0, 1, 2, 3, 4, 5 6
for (int i = 1; i <= 5; ++i) 1, 2, 3, 4, 5 5

A loop that makes one turn too many or one too few has an off-by-one error. It is the most common mistake in loops, and the program still compiles and runs.

Two forms are worth knowing by heart, because each makes exactly n turns.

  • for (int i = 0; i < n; ++i) counts 0, 1, up to n - 1. Use it when the value is used to calculate a position, as the squares above do.
  • for (int i = 1; i <= n; ++i) counts 1, 2, up to n. Use it when the values themselves are wanted, as in "print 1 to n".

When you are unsure, ask two questions: what is i on the first turn, and what is i on the last turn?

Adding up as you go

A loop can build an answer one turn at a time. This program adds the odd numbers from 1 to 9.

#include <iostream>

int main() {
    int total = 0;
    for (int i = 1; i <= 9; i += 2) {
        total += i;
    }
    std::cout << total << "\n";
}
25

The pattern has two statements, and their places matter.

  • Before the loop, the total gets its start value: int total = 0;.
  • Inside the loop, something is added to it: total += i;.
Turn i total after the turn
1 1 1
2 3 4
3 5 9
4 7 16
5 9 25

The total is kept from one turn to the next. That only works because its first statement is outside the loop. In the next program a line total = 0; has been put inside the body.

#include <iostream>

int main() {
    int total = 0;
    for (int i = 1; i <= 9; i += 2) {
        total = 0;
        total += i;
    }
    std::cout << total << "\n";
}
9

Every turn now begins by throwing away what the turns before it added. Only the last turn's 9 is left.

Counting is the same pattern with ++count; in the body: start at 0 before the loop, add one inside it.

A loop inside a loop

The body of a loop can hold any statements, and a loop is a statement. A loop inside another loop is a nested loop.

#include <iostream>

int main() {
    for (int shelf = 1; shelf <= 3; ++shelf) {
        for (int box = 1; box <= 2; ++box) {
            std::cout << "shelf " << shelf << ", box " << box << "\n";
        }
    }
}
shelf 1, box 1
shelf 1, box 2
shelf 2, box 1
shelf 2, box 2
shelf 3, box 1
shelf 3, box 2

The inner loop is the whole body of the outer loop. So on each turn of the outer loop, the inner loop runs from its start to its end. box goes 1, 2 and the inner loop is over. Only then does shelf move on, and the inner loop begins again from int box = 1.

The inner variable changes fastest. The line is printed 3 times 2, which is 6 times.

Two loops give two numbers to draw with: one for the position across, one for the position down.

#include "scimigo.h"
using namespace scimigo;

int main() {
    canvas(600, 400);
    for (int row = 0; row < 3; ++row) {
        for (int col = 0; col < 5; ++col) {
            circle(100 + col * 100, 100 + row * 100, 30, "teal");
        }
    }
}

col decides x, so a larger col is further right. row decides y, so a larger row is lower. The picture is drawn one row at a time, each row from left to right. Swap row and col inside the circle call and the program draws five rows of three.

The inner loop's test may use the outer loop's variable. Then the inner loop makes a different number of turns each time.

#include <iostream>

int main() {
    for (int row = 1; row <= 4; ++row) {
        for (int k = 1; k <= row; ++k) {
            std::cout << k;
        }
        std::cout << "\n";
    }
}
1
12
123
1234

On the outer loop's first turn row is 1, and the inner loop makes one turn. On its fourth turn row is 4, and the inner loop makes four. The statement std::cout << "\n"; is in the outer loop but not in the inner one, so it runs once for each row.

Leaving early and skipping

Two statements change the course of a loop from inside its body.

break; leaves the loop at once. The rest of the body is skipped, the test is not worked out again, and the program carries on after the loop's closing brace.

#include <iostream>

int main() {
    for (int i = 1; i <= 100; ++i) {
        if (i * i > 200) {
            std::cout << i << "\n";
            break;
        }
    }
}
15

The header says "up to 100", but the loop stops at 15, the first number whose square is more than 200. Nothing is printed for 16 or after.

continue; skips the rest of this turn only. The loop itself goes on: a for loop runs its update next, and then its test.

#include <iostream>

int main() {
    for (int i = 1; i <= 8; ++i) {
        if (i % 3 == 0) {
            continue;
        }
        std::cout << i;
    }
    std::cout << "\n";
}
124578

For 3 and 6 the continue runs, so the output statement below it does not.

Both statements act on the loop they are written in. Inside a nested loop, break leaves the inner loop only.

Take care with continue in a while loop. If it comes before the update, the update is skipped too, the variable never changes, and the loop is infinite.

Remembering what the loop found

Often a loop searches for something, and the program needs to know afterwards whether it was found. A bool set before the loop holds the answer.

#include <iostream>

int main() {
    int n = 144;
    bool is_square = false;
    for (int i = 1; i <= n; ++i) {
        if (i * i == n) {
            is_square = true;
            break;
        }
    }
    if (is_square) {
        std::cout << n << " is a square\n";
    } else {
        std::cout << n << " is not a square\n";
    }
}
144 is a square

The bool starts with the answer for "nothing found". The loop changes it at most once, and then leaves, because one find settles the question. The answer is printed after the loop, never inside it: inside, the program does not yet know.

Test at the end

A while loop tests first, so its body may run zero times. Sometimes the body must run once before there is anything to test. The do-while loop tests at the end.

#include <iostream>

int main() {
    int n = 0;
    do {
        std::cout << "n is " << n << "\n";
        --n;
    } while (n > 0);
    std::cout << "after\n";
}
n is 0
after

The body runs, and then the test n > 0 is worked out. It is false, so the loop ends after one turn. A while (n > 0) loop with the same body would print no n is line at all.

Two details of the spelling: the test comes after the closing brace, and the line ends with a semicolon.

The usual job for this loop is asking again. The question has to be asked once before an answer exists.

#include <iostream>

int main() {
    int answer = 0;
    do {
        std::cout << "What is 6 * 7?\n";
        std::cin >> answer;
    } while (answer != 42);
    std::cout << "Correct\n";
}
36 48 42
What is 6 * 7?
What is 6 * 7?
What is 6 * 7?
Correct

answer is declared before do, not inside the braces. A variable declared inside the braces ends at the closing brace, and the test comes after that brace.

Until the input runs out

In module 4 you tested one read: if (std::cin >> x) is true only when the read worked. Put the same read in a while, and the loop goes on for as long as there is another value.

#include <iostream>

int main() {
    double price = 0;
    double total = 0;
    int items = 0;
    while (std::cin >> price) {
        total += price;
        ++items;
    }
    std::cout << "Items: " << items << "\n";
    std::cout << "Total: " << total << "\n";
}
2.5 4 1
Items: 3
Total: 7.5

The test of this loop does two things: it reads the next value into price, and it answers whether that worked.

Test number The read Worked? total after the turn items
1 2.5 true 2.5 1
2 4 true 6.5 2
3 1 true 7.5 3
4 nothing is left false the loop is over

The program does not know in advance how many values there are, and it does not need to. In the lab, the input is what is in the Input box, and it runs out when the last value there has been read. The values can be on one line or on several.

A read also fails when the next thing in the input is not a value of the right type. With the input 2.5 4 one 1 this loop would stop at one, with two items read. It does not skip the word and go on to the 1.

With no input at all, the first test is already false and the body never runs. The program prints Items: 0. If your program divides by the number of values it read, that is the case to think about before you divide.

Your turn

Now try it yourself

Predict what a program will do, run it, and step through it line by line. The checks tell you when your own code works.

Loading the lab…

In this lab

  1. How many times?

    This program has a while loop. Decide what it prints before you run it.

  2. Three parts

    Here is the same program again. Find its three parts: the start value, the test and the update.

  3. A shorter spelling

    This program has no loop. It changes i three times, in three spellings, and prints i after each change.

  4. The same loop on one line

    This program has two loops. The first is a while loop with its three parts on three lines. The second is a for loop.

  5. Ten circles

    This program draws three circles, each written out by hand, 50 apart.

    Replace the three statements with a for loop that draws ten circles. The first stays at x = 50, and each next one is 50 further right. The loop's body has one circle call.

  6. Ten or eleven?

    Four loops, with four different first lines. Each loop does nothing but count its own turns, in a, b, c and d.

    For each loop, write down the first and the last value of i before you answer.

  7. Adding up as you go

    This loop builds a total. On paper, draw a table with the columns turn, i and total after the turn, and fill in one row for each turn. Then answer.

  8. Rows and columns

    One loop is inside another. The program prints six lines, each with the values of row and col.

  9. Checkerboard

    This program draws a grid of 8 rows and 8 columns of squares, all in the colour "wheat".

    Make it a checkerboard: draw a square in "saddlebrown" when row + col is odd, and in "wheat" otherwise. Keep the two loops as they are.

    A number is odd when its remainder after dividing by 2 is 1.

  10. Leave early, skip one

    Two loops with the same first line. One has break where the other has continue. Each prints its numbers on one line.

  11. At least once

    Both loops have the test n < 5, and n is 10 from the start. One tests before its body, the other after.

  12. Until the input runs out

    This program reads whole numbers for as long as it can, and counts them. The Input box holds 4 8 15.

  13. Sum and average

    Read whole numbers until the input runs out. Then print three lines: how many numbers there were, their sum, and their average.

    For the input 3 4 4 the output is exactly:

    Count: 3
    Sum: 11
    Average: 3.66667
    

    The average keeps its fraction. Print it as std::cout prints a double, with nothing added.

    With no numbers at all there is nothing to divide by. Then the output is exactly:

    Count: 0
    Sum: 0
    Average: none
    
  14. FizzBuzz

    Read a whole number n. Print the numbers from 1 to n, one on each line, with three exceptions:

    • for a multiple of 3, print Fizz in place of the number;
    • for a multiple of 5, print Buzz in place of the number;
    • for a multiple of both 3 and 5, print FizzBuzz in place of the number.

    For the input 5 the output is exactly:

    1
    2
    Fizz
    4
    Buzz
    

    If n is 0, print nothing.

  15. Staircase

    Read a whole number n from 1 to 12 and draw a staircase of n columns, built from squares 30 wide and 30 high.

    • The columns are numbered from 1. Column col has its left edge at x = col * 30.
    • Column col is a pile of col squares: column 1 has one square, column 2 has two, and so on.
    • Every pile stands on the line y = 380. The lowest square of a pile has its top edge at y = 350, the next one at y = 320, and so on upward.

    Use any one colour. Draw nothing else.

    For n = 4 the picture has 1 + 2 + 3 + 4 = 10 squares.

  16. Is it prime?

    A whole number is prime when it is 2 or more and no whole number from 2 up to one less than itself divides it. So 2, 3, 5 and 7 are prime; 1 is not, and 9 is not, because 3 divides it.

    Read a whole number n from 0 to 1000000. Print one line: the number, then is prime or is not prime.

    For the input 49 the output is exactly:

    49 is not prime
    

    Try divisors one after another, starting at 2, and leave the loop at the first one that divides n. d divides n when n % d is 0.

  17. Times table

    Print the multiplication table from 1 to 9. It has nine lines of nine products, and every product is printed in a column four characters wide, with std::setw(4).

    The first three lines are exactly:

       1   2   3   4   5   6   7   8   9
       2   4   6   8  10  12  14  16  18
       3   6   9  12  15  18  21  24  27
    

    and the last line ends with 72 81. Nothing comes after the last product of a line except \n.

    std::setw needs its own header (module 3).

  18. Digit cubes

    153 is an unusual number: 1 * 1 * 1 + 5 * 5 * 5 + 3 * 3 * 3 is 153 again. The cubes of its digits add up to the number itself.

    Print every number from first to last, both included, that has this property, one on each line. With the values in the starter, the first line of the output is 153.

    The checks run your program again with other values of first and last. Both are always three-digit numbers.

    You have the tools for the three digits from module 2: / and %.

  19. Digit sum

    Read a whole number that is 0 or more, and at most 2000000000. Print the sum of its digits on one line.

    For the input 1999 the output is 28, because 1 + 9 + 9 + 9 is 28. For the input 0 the output is 0.

    The program does not know how many digits the number has. n % 10 is the last digit of n, and n / 10 is n without its last digit.

  20. Ask until it is valid

    Ask for a number from 1 to 10, and keep asking until one is given.

    Before every read, print this line:

    Number from 1 to 10?
    

    When a number from 1 to 10 has been read, stop asking and print the number and how many reads it took. For the input 0 11 7 the output is exactly:

    Number from 1 to 10?
    Number from 1 to 10?
    Number from 1 to 10?
    Number: 7
    Attempts: 3
    

    The input holds whole numbers only, and one of them is from 1 to 10. Use a do-while loop: the question must be asked once before there is a number to test.

  21. Largest so far

    Read whole numbers until the input runs out, and print the largest of them. For the input 3 9 4 the output is exactly:

    Largest: 9
    

    The numbers may all be negative: for -7 -3 -12 the output is Largest: -3.

    With no numbers at all, the output is exactly:

    No numbers
    
  22. Triangle of stars

    Read a whole number n that is 1 or more. Print a triangle of n lines: line 1 has one *, line 2 has two, and so on up to n. Then print the same triangle upside down, from n stars back to one.

    For the input 3 the output is exactly:

    *
    **
    ***
    ***
    **
    *
    

    The longest line is printed twice. No line has a space in it.

  23. Trace a loop by hand

    Do not run this program yet.

    On paper, draw a table with the columns turn, i, skipped? and total after the turn. Fill in one row for every turn the loop makes, and write down what the last line prints.

    Then add one statement to the program that prints i and total at the end of each turn, run it, and compare its output with your table, row by row.

    Nothing checks this one. When you have compared, go through the list below.