5.1.6 · D5C Programming

Question bank — Control flow — if - else, switch, while, do-while, for, break, continue, goto

2,364 words11 min readBack to topic

Six pictures to hold in your head first

Before the traps, look at these blueprints. Each one turns a rule that this page tests into a picture, so when a question fires you can see the answer instead of simulating it in your head.

1 · Truthiness — the number line of "true"

In C there is no separate "true"/"false" value. A condition is just a number, and the rule is: exactly 0 is false, everything else is true. The figure paints the whole number line: one single amber dot at zero marked FALSE, and the entire rest of the line — negatives, positives, 0.1, -3 — glowing cyan and marked TRUE.

Figure — Control flow — if - else, switch, while, do-while, for, break, continue, goto

2 · if (x = 0) vs if (x == 0) — a memory snapshot

The = versus == trap is really about what happens to the memory box named x. The figure shows two timelines side by side. On the left, x = 0: the box (starting at, say, 7) is overwritten to 0, and the value handed to the if is the just-stored 0 → false. On the right, x == 0: the box is read, not touched, and the comparison hands back a fresh true/false.

Figure — Control flow — if - else, switch, while, do-while, for, break, continue, goto

3 · while (pre-test) vs do-while (post-test) — flowcharts

These two loops differ by where the diamond sits. The figure draws both flowcharts. In while, the condition diamond is at the top, so if it is false on entry the body box is never touched — the arrow skips straight to "exit." In do-while, the body box comes first and the diamond is at the bottom, so the body always runs once before any test.

Figure — Control flow — if - else, switch, while, do-while, for, break, continue, goto

4 · switch fall-through — a computed jump into one block

switch is not a stack of separate boxes; it is one block you jump into. The figure shows a single tall block with case labels as entry arrows on its left edge. Execution lands on the matching label and then flows straight down through every following case until it hits a red break bar (or the bottom). The x == 1 path is drawn in amber falling through one into two.

Figure — Control flow — if - else, switch, while, do-while, for, break, continue, goto

5 · continue in for vs while — where the arrow lands

continue means "skip the rest of the body," but where it jumps next differs. The figure overlays both loops. In the for loop the continue arrow lands on the update i++ (so the counter advances). In the hand-written while loop with i++ placed at the bottom, continue jumps past the i++ straight to the condition — the counter freezes and the loop hangs.

Figure — Control flow — if - else, switch, while, do-while, for, break, continue, goto

6 · while (1) and the three escape hatches

An "infinite" loop never ends through its own condition — that is what self-terminate means: stopping because the loop's own diamond turned false. while (1) can never self-terminate (the diamond is always true), but it can still be escaped by a jump. The figure shows the loop as a closed cyan ring with three amber exit arrows breaking out of it: break, return, and goto.

Figure — Control flow — if - else, switch, while, do-while, for, break, continue, goto

True or false — justify

In C, if (0.0) runs its block because 0.0 is a valid number.
False. "True" means non-zero (figure 1); 0.0 sits on the amber FALSE dot, so the block is skipped. Any non-zero value like -3 or 0.1 sits in the cyan TRUE sea and would run it.
if (x = 0) and if (x == 0) behave the same way.
False. Per figure 2, x = 0 assigns 0 (a side effect on the box) and evaluates to 0 → false; x == 0 reads the box and compares. Opposite behaviour and different memory effects.
A switch can branch on a float variable.
False. switch only accepts an integral expression (int, char, enum, etc.) because it compares against constant labels; floats are not allowed by the standard.
while (1) { ... } is always an infinite loop with no way out.
False. It never self-terminates via its condition (figure 6), but the three amber escape hatches — break, return, goto — can still leave it.
A do-while loop can execute its body zero times.
False. In figure 3 the body box comes before the diamond, so do-while runs the body at least once, even when the condition is false from the start.
continue inside a switch skips to the next case.
False. continue only affects loops, not switch. Inside a switch with no enclosing loop, continue is a compile error; if a loop encloses the switch, continue jumps to that loop's update — not the next case.
break and goto do the same job in a single loop.
False. break exits one enclosing loop/switch; goto can jump anywhere in the function — including out of nested loops that a single break cannot escape.
Two for loops with identical bodies always run the same number of times as the equivalent while versions.
True for the count, but continue behaves differently (figure 5): in for the update still runs; a naive while translation may skip the update and loop forever.
for (;;) is invalid because it has empty parts.
False. All three for parts are optional; empty init/update do nothing and an empty condition is treated as always true, so for(;;) is a legal infinite loop.
An else always pairs with the nearest unmatched if.
True. This is the "dangling else" rule — else binds to the closest preceding if in the same block, which is why braces matter when nesting.

Spot the error

if (score = 90) printf("A"); — what's wrong?
= assigns 90 to score (figure 2's side effect); the expression is 90 (non-zero → always true), so it prints "A" regardless of the real score. Use ==.
switch (x) { case 1: printf("one"); case 2: printf("two"); }
What happens when x == 1?
It prints onetwo. Case 1 has no break, so execution falls through into case 2's code — trace the amber waterfall in figure 4. Add break; after each case.
int i = 0;
while (i < 3) {
    if (i == 1) continue;
    printf("%d", i);
    i++;
}
Why does this hang?
When i == 1, continue jumps back to the condition before i++ runs (the red arrow in figure 5), so i stays 1 forever — an infinite loop. The update must run before any continue in a while.
do { x++; } while (x < 5)
printf("done");
What's the compile error?
A do-while requires a semicolon after while (x < 5). Without it the parser sees while(...) printf(...) as a new loop and fails.
for (int i = 0; i < 3; i++);
    printf("%d", i);
Why does this misbehave?
The stray ; after the for header makes the loop body empty; the printf runs once after the loop and also can't see i (out of scope) → compile error or wrong output.
if (a > 0)
    printf("pos");
    printf("also runs?");
Does the second line only run when a > 0?
No. Without braces, only the first statement is the if body. printf("also runs?") is outside the if and always runs — indentation lies here.
for (int i = 0; i < N; i++)
    for (int j = 0; j < M; j++)
        if (found) break;
printf("out");
Does break exit both loops?
No — break exits only the inner j loop; the outer i loop keeps going. To escape both at once you need a goto (or a flag).

Why questions

Why does C use "non-zero = true" instead of a dedicated boolean?
Early C (1972) had no boolean type at all — a condition was literally "is this integer non-zero?", which is one cheap CPU test. Only in C99 did _Bool/<stdbool.h> arrive for readability, but they store 0/1 and the underlying non-zero rule (figure 1) never changed.
Why does switch fall through instead of stopping at each case?
A switch compiles to a computed jump into one block of code, not separate boxes (figure 4). Once execution lands on a label it keeps flowing downward — break is what turns that flow off.
Why choose do-while over while for menu input?
You must show the menu and read input at least once before you can decide whether to repeat. do-while runs the body first and asks after (figure 3, right), matching "do, then check."
Why is goto accepted for nested-loop exit but frowned on elsewhere?
A single forward goto to a clearly-labelled exit is easy to follow and does what break can't (escape many loops). Backward/arbitrary jumps create "spaghetti" control flow that no reader can trace.
Why write if (5 == x) instead of if (x == 5)?
A typo 5 = x is a compile error (can't assign to a constant), so this "Yoda condition" catches the = vs == mistake automatically, whereas x = 5 compiles silently (figure 2).
Why does the loop variable in for (int i = ...) disappear after the loop?
A variable declared in the for header has loop scope — it lives only inside the loop. This prevents accidental reuse and is one difference from the while equivalent where the variable outlives the loop.

Edge cases

What does while (i < 3) do if i starts at 5?
Nothing — the diamond is at the top (figure 3, left), false on the first test, so the body runs zero times.
What does do { ... } while (i < 3) do if i starts at 5?
The body runs once (acting with i = 5) because it sits before the diamond (figure 3, right), then the test fails and the loop exits. do-while guarantees one execution.
In switch, what happens if no case matches and there is no default?
Nothing runs — no label matches, so there is nowhere to jump into and control skips the whole block. Without a default, an unmatched value silently does nothing.
Where does continue go inside a for loop versus a while loop?
In a for, continue jumps to the update then the condition, so i++ still runs (cyan path, figure 5). In a hand-written while with i++ at the bottom, it jumps straight to the condition, skipping the update — the infinite-loop trap (red path, figure 5).
What does break do when there is no loop or switch around it?
It's a compile errorbreak has nothing to exit. It is only legal inside a loop or a switch.
Can a goto jump into the middle of a loop from outside it?
The label must be in the same function, but jumping in skips the loop's initialization arrow, so the body reads variables that were never set up (undefined behaviour). Prefer jumping out, not in — that is the safe direction shown by figure 6's exit arrows.

Recall One-line self-test

Say each aloud: non-zero = true; = is assignment; switch falls through until break; while tests before, do-while tests after; break exits one level, goto exits all levels.