SEN2201 · Week 11 · Programming in C

C control structures: if, switch, while, for, do-while

Decision and loop structures, break/continue, fall-through in switch, common traps (= inside an if, the dangling else, ; after a for) and their counterpart in LC-3 branches.

control structureconditionalif-elsedangling elseswitchcasefall-throughbreakcontinuewhile loopfor loopdo-while looploop countersentinel

In week 10 you built loops and ifs by hand with BR instructions. In C the same structures are written with keywords like if, while, for; the compiler translates them into the BR patterns you wrote. This page explains the rule of each structure and the points where the exam sets the most traps. The question type is again “What is printed?”.

if and if-else

int score = 72;
if (score >= 85) printf("AA\n");
else if (score >= 70) printf("BB\n");
else if (score >= 50) printf("CC\n");
else printf("FF\n");
BB

The conditions are tested from top to bottom, the block of the first true one runs, and the rest are skipped.

PITFALL · = versus ==. if (x = 5) assigns 5 to x and the value of the expression is 5, always true. The compiler usually gives only a warning. When you see this code in the exam, write the output according to the assignment.

Dangling else

if (a == 0)
    if (b == 0) printf("A\n");
else printf("B\n");

The indentation makes you think the else belongs to the outer if. The rule is not that: the else attaches to the nearest unmatched if. That is, it is the else of the inner if (b == 0). When a = 1 nothing is printed. To make your intent clear, always use { }.

switch

switch (expression) {
    case CONST1: ... break;
    case CONST2: ... break;
    default: ...
}

Execution jumps to whichever case the value of the expression matches, and continues until a break (or until the switch ends). If there is no break, the code of the cases below also runs: fall-through.

int d = 1;
switch (d) {
    case 0: printf("zero ");
    case 1: printf("one ");
    case 2: printf("two ");
}
one two

Case labels must be constants (int or char). You cannot write case x > 5:.

while

int n = 3;
while (n > 0) {
    printf("%d ", n);
    n--;
}
printf("go\n");
3 2 1 go

The condition is tested first. If it is false at the start, the body never runs.

The LC-3 counterpart (n in R0):

LOOP    ADD  R0, R0, #0    ; set the CC according to n
        BRnz DONE          ; exit if n <= 0
        ...                ; body
        ADD  R0, R0, #-1   ; n--
        BRnzp LOOP
DONE    ...

for

for (init; condition; update) body;

It is the same as:

init;
while (condition) { body; update; }
int i;
for (i = 1; i <= 4; i++)
    printf("%d ", i * i);
1 4 9 16

The trace table

Solve loop questions with a table:

for (i = 10; i > 0; i /= 2) c++;

i     i > 0?   c
10    yes      1
5     yes      2
2     yes      3
1     yes      4
0     no       (ends)

PITFALL · a semicolon after the for. for (i = 0; i < 5; i++); is a loop with an empty body. The line below, whatever its indentation, runs once after the loop ends and sees i = 5.

do-while

do {
    body;
} while (condition);

The body runs first, the condition is tested afterwards. So it runs at least once. It is ideal for menu loops (“ask until the user enters 0”). The ; at the end is required.

break and continue

  • break: leave the innermost loop or switch immediately.
  • continue: skip the rest of this round and move on to the next one. In a for, the update part (i++) still runs.
for (i = 0; i < 10; i++) {
    if (i % 3 == 0) continue;   /* 0, 3, 6 are skipped */
    if (i > 7) break;           /* leave at 8 */
    printf("%d ", i);
}
1 2 4 5 7

Nested loops

In each round of the outer loop, the inner loop runs from start to end.

int i, j;
for (i = 1; i <= 3; i++) {
    for (j = 0; j < i; j++)
        printf("*");
    printf("\n");
}
*
**
***

The total number of inner rounds: 1 + 2 + 3 = 6. In “how many times does it run?” questions, write down how many times the inner loop runs for each outer round and add them up.

Worked trace: the Collatz sequence

If n is even halve it, if odd make it 3n + 1; continue until you reach 1.

int n = 6, steps = 0;
while (n != 1) {
    if (n % 2 == 0) n = n / 2;
    else n = 3 * n + 1;
    printf("%d ", n);
    steps++;
}
printf("\n%d\n", steps);
3 10 5 16 8 4 2 1
8

When building the trace table, write three things on each row: the result of the condition, which branch ran, and the new values of the variables.

n    n != 1?   branch     new n   steps
6    yes       even       3       1
3    yes       odd        10      2
10   yes       even       5       3
5    yes       odd        16      4
16   yes       even       8       5
8    yes       even       4       6
4    yes       even       2       7
2    yes       even       1       8
1    no        (ends)

The LC-3 counterpart of the for loop

int s = 0, i;
for (i = 1; i <= 4; i++) s += i;     /* s = 10 */

The compiler (s in R0, i in R1) produces roughly this:

        AND  R0, R0, #0     ; s = 0
        AND  R1, R1, #0
        ADD  R1, R1, #1     ; i = 1          (init)
LOOP    ADD  R2, R1, #-5    ; i - 5
        BRzp DONE           ; exit if i >= 5  (the opposite of the condition)
        ADD  R0, R0, R1     ; s += i          (body)
        ADD  R1, R1, #1     ; i++             (update)
        BRnzp LOOP
DONE    HALT

In the simulator the result is R0 = 10, R1 = 5. The test i <= 4 turns into the question “is i - 5 negative?”: in the LC-3 a comparison always means a subtraction + the condition codes. If the condition is true it falls into the body; if false (z or p) it jumps out of the loop.

Ready-made loop patterns

JobPattern
Sum from 1 to nfor (i = 1; i <= n; i++) s += i;
Digit sumwhile (n > 0) { s += n % 10; n /= 10; }
Number of digitswhile (n > 0) { c++; n /= 10; }
Read with a sentinelwhile (x != 0) { ...; scanf("%d", &x); }
Ask at least oncedo { ... } while (answer != 0);

Common mistakes

Wrong ideaThe truth
if (x = 5) compares x with 5It assigns; always true
else attaches by indentationIt attaches to the nearest if
switch runs the matching case and leavesWithout break it falls into the ones below
do-while never runs if the condition is falseIt runs at least once
The line after for (...); is in the loopThe loop is empty, the line runs once
continue ends the loopIt only skips this round
break leaves all nested loopsOnly the innermost
case x > 5: is validA case must be a constant

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

What is printed?

int x = 0;
if (x = 5) printf("yes %d\n", x);
else printf("no %d\n", x);
Show answer
yes 5

x = 5 is an assignment, not a comparison. 5 is written into x and the value of the expression is 5; since 5 is not zero, it is true. A comparison needs ==.

Question 2hard

What is printed?

int a = 1, b = 0;
if (a == 0)
    if (b == 0) printf("A\n");
else printf("B\n");
printf("end\n");
Show answer
end

The else attaches not to the indentation but to the nearest unmatched if (dangling else): it is the else of if (b == 0). Because the outer if (a == 0) is false, the inner if-else never runs. Only end is printed.

Question 3medium

What is printed?

int i = 1, s = 0;
while (i <= 10) {
    s += i;
    i += 3;
}
printf("%d %d\n", s, i);
Show answer
22 13

The body runs for i = 1, 4, 7, 10: s = 1 + 4 + 7 + 10 = 22. Then i = 13, the condition is false.

Question 4easy

What is printed?

int i;
for (i = 2; i < 15; i += 4)
    printf("%d ", i);
Show answer
2 6 10 14

The condition is true for i = 2, 6, 10, 14. It ends when i = 18.

Question 5easy

What is printed?

int n = 10;
do {
    printf("%d ", n);
    n++;
} while (n < 5);
Show answer
10

do-while tests the condition AFTER the body, so the body runs at least once. 10 is printed, n = 11, 11 < 5 is false, the loop ends.

Question 6medium

What is printed?

int k = 2;
switch (k) {
    case 1: printf("one ");
    case 2: printf("two ");
    case 3: printf("three ");
            break;
    default: printf("other ");
}
Show answer
two three

It jumps to case 2. Because there is no break, it falls into the next case (fall-through) and three is printed too. At break the switch ends, default does not run.

Question 7medium

What is printed?

int i;
for (i = 0; i < 10; i++) {
    if (i % 3 == 0) continue;
    if (i > 7) break;
    printf("%d ", i);
}
Show answer
1 2 4 5 7

continue skips the rest of that round (i = 0, 3, 6). break ends the loop: at i = 8, 8 % 3 ≠ 0, 8 > 7 → break. What is printed is 1 2 4 5 7.

Question 8medium

What is printed?

int i, j, c = 0;
for (i = 0; i < 4; i++)
    for (j = i; j < 4; j++)
        c++;
printf("%d\n", c);
Show answer
10

The inner loop runs 4 times for i = 0, 3 times for i = 1, 2 times for i = 2, 1 time for i = 3: 4 + 3 + 2 + 1 = 10.

Question 9hard

What is printed?

int i;
for (i = 0; i < 5; i++);
    printf("%d\n", i);
Show answer
5

The ; at the end of the for is an empty body. The loop spins 5 times doing nothing, and i = 5. Despite the indentation, the printf is outside the loop and runs once.

Question 10medium

How many times does the loop body execute, and what is printed?

int i, c = 0;
for (i = 10; i > 0; i /= 2)
    c++;
printf("%d\n", c);
Show answer
4

The body runs for i = 10, 5, 2, 1 (integer division: 5 / 2 = 2, 1 / 2 = 0). It ends when i = 0.

Question 11easy

What is printed?

int n = 4096, s = 0;
while (n > 0) {
    s += n % 10;
    n /= 10;
}
printf("%d\n", s);
Show answer
19

Digit sum: n % 10 takes the last digit, n / 10 drops it. 6 + 9 + 0 + 4 = 19.

Question 12hard

A C compiler translates if (x < 0) x = -x; for the LC-3, with x already loaded into R0. Which branch instruction skips the assignment?

Show answer
BRzp

The pattern: skip with the opposite of the condition. If x < 0 is not true (that is x ≥ 0, z or p), the assignment must be skipped: BRzp SKIP. After that, NOT R0, R0 / ADD R0, R0, #1 / STR updates x. The same as the absolute value program in week 8.

Verification: Every code snippet was compiled and run as C99 with Zig cc (clang), and the outputs were copied exactly (verify/SEN2201/c/w11b.c and w11c.c, node verify/SEN2201/c/run.mjs w11); the LC-3 counterpart of the for loop was run on our own simulator (end of verify/SEN2201/08.mjs).

Review card

if (x = 5) is an assignment! its value is 5 -> true. Comparison is == else attaches to the nearest unmatched if (indentation is irrelevant) -> use { } while: test first | do-while: body first (at least 1 time) | for(init; test; update) for (...); -> empty body, the line below runs ONCE after the loop switch: jump to the matching case, without break FALL INTO THE ONES BELOW | default: if none matches a case label must be a constant (int/char), no ranges break: leave the innermost loop/switch | continue: skip this round (in a for the update runs) Nested: j = i..n-1 -> n + (n-1) + ... + 1 i /= 2 loop: 10,5,2,1 -> 4 rounds Digits: take n%10, drop n/10 LC-3: if -> skip with the OPPOSITE of the condition (BRzp for x<0) | while -> test at the start + BRnzp back at the end