Foundations · Iteration
Dry-run the loop before you trust it
A loop is three decisions: where to start, when to stop, what changes each pass. Fill in a trace table by hand and all three become visible — along with every off-by-one and every loop that never ends.
Build the trace table for 4729, one cell at a time →01 The idea
Three decisions, spread across time
A loop is how a program does the same thing many times without you typing it many times. Every loop in every language is built from the same three decisions: where the counter starts, when the loop stops, and what changes on each pass. Get the first wrong and your total is garbage. Get the second wrong and the program hangs. Leave out the third and the second can never happen.
What makes loops hard is that their behaviour is spread across time. You cannot see it by reading, because reading is one pass and the loop is many. So you make it visible: draw a table with one column per variable and one row per pass, then fill it in by executing the code in your head, one statement at a time. That is a dry run, and in Stage 0 the table is what earns the marks, not just the final number.
02 Worked example
Sum the digits of 4729, on paper
The loop takes the last digit off 4729 and adds it to a running total, then throws that digit away. Three columns, one per variable: n, digit and sum. Each row holds the values at the end of that pass, so the n column already has the digit removed. The pink column is the digit destroyed on that pass.
Write that last row down. The check that fails is part of the table, and leaving it out is the single most common way to drop marks on a dry-run question. Now read the sum and n columns together, row by row: 0 and 4729, then 9 and 472, then 11 and 47, then 18 and 4, then 22 and 0. The digits still sitting inside n plus the total already collected in sum add to 22 on every single row: 0+22, 9+13, 11+11, 18+4, 22+0. That sentence is a loop invariant. It is true at the top of every pass, which is why the loop is right for any number and not just this one.
03 Mechanics
while and for are the same three parts
These two programs are the same loop. Both print 22 for 4729, both take four passes, and both produce the trace table you just filled in. The only difference is where the three parts are written down.
while — the three parts scattered
n = 4729 // startsum = 0while n > 0: // stop digit = n % 10 sum = sum + digit n = n / 10 // stepprint sum
for — the three parts in one header
sum = 0for (n = 4729; n > 0; n = n / 10): digit = n % 10 sum = sum + digitprint sum
The three parts did not change, only their addresses did. Start is n = 4729, stop is n > 0, step is n = n / 10. On the left they sit on lines 1, 3 and 6 and you have to hunt for them. The for header puts all three side by side, which is why it is the usual spelling when you already know the pass count before you start — walking an array of length 5, say. For this loop either spelling is correct, and while reads more naturally, because you cannot say how many passes it needs until the digits are gone.
The step line is the one that ends the loop. Delete line 6 on the left and n stays 4729 for ever, so n > 0 stays true for ever. The for version makes that mistake visible: an empty third slot in the header is something you can see, a missing last line of a body is not.
A do-while moves the check below the body. Same three parts again, but tested after the first pass, so the body always runs at least once. Feed both versions n = 0: the while writes an empty trace table and prints 0, the do-while writes one row — digit = 0, sum = 0, n = 0 — and also prints 0. Same answer, different tables, and the table is what gets marked.
Off-by-one, counted rather than argued
| Loop header | Values i actually takes | Passes |
|---|---|---|
| i = 0; i < 5 | 0 1 2 3 4 | 5 |
| i = 0; i <= 5 | 0 1 2 3 4 5 | 6 |
| i = 1; i <= 5 | 1 2 3 4 5 | 5 |
| i = 1; i < 5 | 1 2 3 4 | 4 |
| i = 5; i > 0; i-- | 5 4 3 2 1 | 5 |
05 Cheat sheet
Five constructs and the mistake each one invites
| Construct | Body runs | The mistake it invites |
|---|---|---|
while (cond) | 0 or more times — checked before the first pass | Leaving out the step line, so cond can never turn false |
for (init; cond; step) | 0 or more times — the same three parts, one header | Changing the counter inside the body as well as in the header |
do { } while (cond) | 1 or more times — checked after the first pass | Using it when empty input must produce zero passes |
break | Ends the loop now — no step, no further check | Breaking out of only the inner loop of a nested pair |
continue | Skips the rest of the body — in a for the header step still runs, in a while nothing runs | In a while it skips the step line at the bottom, so the loop hangs |
06 Where & why
A slow tool you will be graded on
A trace table is slow. Writing out four passes of a six-line loop takes about a minute by hand. That is the trade: it is the only way to be certain about a loop without running it, and in a written exam or a whiteboard round you cannot run anything.
Fill in a trace table when…
Use something else when…
| Situation | Better choice | Why |
|---|---|---|
| The loop runs hundreds of passes | A print statement inside the body | A table is for reasoning about a handful of passes. Past about ten rows you are copying, not thinking, and copying is where the arithmetic slips creep in. |
| You need to know which pass broke it | A debugger breakpoint with a watch list | The debugger shows the same columns automatically and lets you jump to pass 500. It is a trace table that fills itself in. |
| The loop body calls other functions | Dry-run each function on its own first | A trace table has one column per variable in one scope. A nested call needs its own table, and stacking those tables is exactly what the call stack does. |
| You want to prove the loop is right for every input | An informal loop invariant | One sentence that stays true at the top of every pass covers all inputs at once. A table only proves the input you traced. |
07 Interview questions
What they actually ask
First-round loop questions are almost never about syntax. They are about pass counts, about what a variable holds the moment the loop ends, and about whether you can dry-run something on a whiteboard with no compiler in the room.
What are the three parts of a loop?
When would you use a while loop instead of a for loop?
What does a do-while give you that a while does not?
How many times does for (i = 0; i <= n; i++) run?
What actually causes an infinite loop?
What is the difference between break and continue?
Dry-run this loop for me and show your table.
What is a loop invariant, informally?
Where do you declare the accumulator, and what breaks if you get it wrong?
What is the time complexity of the digit-sum loop?
Would you ever draw a trace table on a real job?
08 Practice problems
Six to trace by hand
Fill in the trace table before you write any code, and include the final row where the condition fails. If the table is right the code is a transcription. If you cannot fill the table, typing faster will not save you.