Loops, counters, accumulators, and invariants

Computer Science I

Initialize; Test; Body; Update.
Original learning diagram: Initialize → Test → Body → Update.

A loop repeats a group of statements. To understand one, track what is true before an iteration, what the body changes, and when repetition stops. Counting how often the body runs is only part of the task; we also need to know which values it processes.

A counter tracks progress or how many observations have been seen. An accumulator combines values, for example by adding them into a running total. They may change on the same iteration but serve different purposes.

Read the three parts of a for loop #

A for loop places initialization, a condition, and an update together. Initialization happens once. The condition is checked before each iteration. If it is true, the body runs, then the update runs, and the next condition is checked.[1]

#include <iostream>

int main() {
    int total = 0;
    for (int value = 1; value <= 4; ++value) {
        total += value;
    }
    std::cout << total << '\n';
}

The total is initialized to zero. The loop initializes value to one and tests whether it is at most four. Since one satisfies the condition, the body adds one to total. The update then increases value to two.

The next test succeeds too. The body adds two to the existing total of one, producing three. Repeating with value three makes total six. Repeating with value four makes total ten. After that iteration the update makes value five. The condition now fails, and execution continues after the loop.

The final statement prints 10 and a newline. It runs once after the loop, rather than printing once per addition.

Record an execution trace #

A trace is a written record of the values as the program executes. For this example, the important states are:

Value before the conditionDoes it pass?Total before the bodyTotal after the body
1Yes01
2Yes13
3Yes36
4Yes610
5No10No body runs

total += value adds the current value to the stored total. It does not replace total with value. ++value advances the loop's counter; it does not add anything directly to total.

Keeping these columns separate helps expose an error such as resetting total to zero inside the body. That would discard earlier work on every iteration.

A rule that remains true as the loop runs #

A loop invariant is a statement that holds each time execution reaches a particular point. Here, just before the condition is checked, total equals the sum of the integers from one through value - 1.

At value one, there are no earlier positive integers to add, and total is zero. After adding the current value and increasing value by one, the statement remains true: total now includes precisely the integers before the new value. When value becomes five, total includes one through four, which is the requested result.

This gives a reason the loop works, beyond observing that one run printed ten. An invariant should name the point where it applies. A statement true before the body need not be true midway through its updates.

Choose the condition from the values needed #

The mathematical integers one through four require the condition value at most four. Array positions use a different convention. For a collection containing n elements, valid positions start at zero and end at n minus one. The pattern i = 0; i < n; ++i therefore visits exactly n positions.

With n equal to four, those positions are zero, one, two, and three. Using an inclusive upper bound would add position four, which is outside that four-element collection. A loop's condition should follow the meaning of the counter, rather than whichever spelling appears familiar.

A while loop checks its condition before the body and can run zero times. A do loop checks after the body and therefore runs at least once. The latter can suit a prompt that must appear before checking the answer, while the former suits processing only when an observation is already available.

Progress and early exits #

A loop must move toward its stopping condition. If value never changes in the example, the condition stays true and repetition does not end.

A continue skips the remaining statements in the current body. In a for loop, execution still reaches the update before the next condition. In a while loop, an update placed later in the body could be skipped by continue, accidentally preventing progress.

A break exits the nearest enclosing loop or switch. It does not automatically exit all surrounding loops. Nested loops need separate reasoning: with two rows and three columns, the inner column loop starts again for each row, visiting six cells altogether. Two full loops each ranging over n positions often perform work proportional to n squared, while one traversal performs work proportional to n.

For numerical approximations, update the existing partial sum when possible instead of recomputing earlier terms. Choose a meaningful stopping error and an iteration limit if convergence is uncertain.

Practice with explained answers #

for (int i = 0; i < 4; ++i) runs four times. Replacing the condition with i at most four makes it run five times. Write down the visited values to see the difference, rather than guessing from the number four.

For the observations -2, 3, and 5, counting positive numbers gives two, while adding the positive numbers gives eight. A mean needs both sum and count: eight divided by two gives four. With no accepted observations, count zero needs a separate response before division.

These loop patterns support array traversal, sorting passes, and repeated-data work throughout CS2.

References

  1. ↑ C++ working draft: iteration statements .