G27
Self-checkedTier 2 19 min readpds.c-control-flow

Control flow and loops

How a C program chooses and repeats: if and else (and the dangling else), while, do-while and for, break and continue, switch with its fall-through, short-circuit evaluation of && and ||, the pitfalls (assignment in a condition, a stray semicolon, off-by-one), tracing a loop by hand, and counting how many times a body runs.

Why it exists

Control flow decides which statements run and how often. In GATE a C question is very often a loop to trace by hand (what is printed, what is the final value), a switch with a missing break, a condition with a side effect that may or may not be evaluated, or a count of how many times a statement runs. The rules are few and exact; the mistakes come from assuming a language that behaves differently (a switch that does not fall through, a && that evaluates both sides, a do-while that tests first).

Prerequisites

You need the operators and the conversions of types and operators: integer division, the meaning of a true condition (any non-zero value), and the difference between = and ==.

Precise definitions

Conditions. In C there is no boolean in a condition: 0 is false, every other value is true. The relational and logical operators produce 0 or 1.

if and else.

if (condition) statement
if (condition) statement else statement

The statement is a single statement, usually a block { ... }. An else belongs to the nearest preceding if that has no else: this is the dangling else; braces change the binding. The conditional expression c ? a : b evaluates a if c is non-zero and b otherwise.

Loops.

looptestsruns the body
while (c) bodybefore each iterationzero or more times
do body while (c);after each iterationat least once
for (init; c; update) bodyinit once; then c before each iteration; update after eachzero or more times

for (init; c; update) body is the same as init; while (c) { body update; } except for continue. Any of the three parts may be empty; an empty condition means true (for (;;) is an endless loop). The comma operator a, b evaluates a, then b, and has the value of b.

break and continue. break leaves the innermost enclosing loop or switch. continue skips the rest of the body and goes to the next iteration: in a for loop it jumps to the update, in a while or do-while to the test.

switch.

switch (integer expression) {
case constant1: statements
case constant2: statements
default: statements
}

The expression must have integer type (including char and enumerations); the case labels are distinct integer constants. Control jumps to the matching label, or to default if none matches (or leaves the switch if there is no default), and then continues through all following statements, crossing the next labels, until a break or the end of the switch: this is fall-through. Several labels in a row (case 3: case 4:) share the code that follows. The default label may stand anywhere and also falls through.

Short-circuit evaluation. a && b evaluates a; if it is 0 the result is 0 and b is not evaluated at all. a || b evaluates a; if it is non-zero the result is 1 and b is not evaluated. There is a sequence point after the left operand, so a side effect in a is complete before b. Side effects in the skipped operand (a function call, i++) do not happen. The result is always 0 or 1. The ordinary operators such as + do not short-circuit, and the order of evaluation of their operands is not specified.

goto. goto label; jumps to a label in the same function. Loops and switch compile into conditional and unconditional jumps (see control flow translation); goto is rarely needed.

Counting iterations. For for (i = a; i < b; i += c) with c>0c > 0 the body runs max⁡(0,⌈(b−a)/c⌉)\max(0, \lceil (b - a)/c \rceil) times; with i *= 2 from 1 to below mm it runs ⌈log⁡2m⌉\lceil \log_2 m \rceil times, with i /= 2 from mm down to above 1 it runs ⌊log⁡2m⌋\lfloor \log_2 m \rfloor times; nested loops multiply, or add up when the inner bound depends on the outer index (for example ∑i=0n−1i=n(n−1)/2\sum_{i=0}^{n-1} i = n(n-1)/2). These counts are what an analysis of the running time (algorithm analysis) uses.

How it works

Four programs, compiled and run for real; the tables are their output, one line per step.

A while loop that peels off the digits of a number: the test n > 0 before every iteration.

A while loop that peels off the digits of 90713: start

Computed by a script, not typed
momentdnsumrev
before the loop
after iteration 1
after iteration 2
after iteration 3
after iteration 4
after iteration 5

Step 0

The loop runs while n > 0. Each pass takes the last digit, adds it to a sum and appends it to a reversed number. digit sum 20, reversed 31709.

0 / 6
real run: the C program printed on the page is compiled with cc -std=c11 -Wall -Wextra -Werror and run; the table is its output. python3 scripts/gen-pds-control-traces.py

A do-while loop: Euclid's algorithm by repeated subtraction. The body runs first, then x != y is tested.

A do-while loop: Euclid's algorithm by subtraction on 84 and 36: start

Computed by a script, not typed
momentxyx != y
start
after step 1
after step 2
after step 3
after step 4

Step 0

The common value at the end is the greatest common divisor, because subtracting the smaller number from the larger does not change the gcd. gcd = 12 after 4 steps.

0 / 5
real run: the C program printed on the page is compiled with cc -std=c11 -Wall -Wextra -Werror and run; the table is its output. python3 scripts/gen-pds-control-traces.py

switch and fall-through.

switch and fall-through: what is printed for each value: start

Computed by a script, not typed
inputprinted
c = 1
c = 2
c = 3
c = 4
c = 0
c = 9

Step 0

Execution enters at the matching case label and runs on, through the following labels, until a break (or the end of the switch). default is entered when no case matches; it can be anywhere in the switch and falls through too.

0 / 6
real run: the C program printed on the page is compiled with cc -std=c11 -Wall -Wextra -Werror and run; the table is its output. python3 scripts/gen-pds-control-traces.py

Short-circuit evaluation: which calls happen.

Short-circuit evaluation of && and ||: start

Computed by a script, not typed
expressionfunctions that were calledresult
f(0) && f(1)
f(1) && f(2)
f(1) || f(0)
f(0) || f(3)
for j = -2..2: if (j > 0 && i++) count += j;

Step 0

&& and || evaluate their left operand first and skip the right one when the left already decides the result. The right operand's side effects (calls, i++) are skipped too.

0 / 5
real run: the C program printed on the page is compiled with cc -std=c11 -Wall -Wextra -Werror and run; the table is its output. python3 scripts/gen-pds-control-traces.py

Counting iterations: the formulas against real runs.

How many times does the body run?: start

Computed by a script, not typed
looptimesformula
for (i = 0; i < n; i++), n = 10
for (i = 0; i < n; i += 3), n = 10
for (i = 1; i < m; i *= 2), m = 100
for (i = m; i > 1; i /= 2), m = 100
for i < n: for (j = 0; j < i; j++), n = 10
for i < n: for (j = i; j < n; j++), n = 10
for i < n: for j < m, n = 10, m = 100
do { } while (i > 0), i = 0
while (i > 0), i = 0

Step 0

Counted by running each loop. The formulas are the ones to remember: a loop with step c over a range n runs about n/c times (rounded up), a doubling or halving loop about log2 n times, and nested loops multiply or sum.

0 / 9
real run: the C program printed on the page is compiled with cc -std=c11 -Wall -Wextra -Werror and run; the table is its output. python3 scripts/gen-pds-control-traces.py

Worked examples

EX 1Tracing a while loop

Easy

Trace the loop by hand with a table of the variables after each iteration, then compare with the run.

#include <stdio.h>
 
int main(void) {
    int n = 90713, sum = 0, rev = 0;
    printf("start: n=%d sum=%d rev=%d\n", n, sum, rev);
    while (n > 0) {
        int d = n % 10;
        sum += d;
        rev = rev * 10 + d;
        n /= 10;
        printf("d=%d n=%d sum=%d rev=%d\n", d, n, sum, rev);
    }
    printf("digit sum %d, reversed %d\n", sum, rev);
    return 0;
}
start: n=90713 sum=0 rev=0
d=3 n=9071 sum=3 rev=3
d=1 n=907 sum=4 rev=31
d=7 n=90 sum=11 rev=317
d=0 n=9 sum=11 rev=3170
d=9 n=0 sum=20 rev=31709
digit sum 20, reversed 31709

Reading it. The test n > 0 is evaluated before each of the five iterations (n = 90713, 9071, 907, 90, 9) and fails when n has become 0. In each iteration d is the last digit, sum accumulates the digits (3+1+7+0+9=203 + 1 + 7 + 0 + 9 = 20) and rev appends each digit on the right, so the last digit taken becomes the first digit of rev: 31709 is 90713 reversed. Note rev = 3170 after the fourth iteration (the digit 0 is appended) and the final 31709. A trace table with one row per iteration is the reliable method.

EX 2A do-while loop and the greatest common divisor

Medium
#include <stdio.h>
 
int main(void) {
    int x = 84, y = 36, step = 0;
    printf("start: x=%d y=%d\n", x, y);
    do {
        if (x > y) x = x - y;
        else y = y - x;
        step++;
        printf("step %d: x=%d y=%d\n", step, x, y);
    } while (x != y);
    printf("gcd = %d after %d steps\n", x, step);
    return 0;
}
start: x=84 y=36
step 1: x=48 y=36
step 2: x=12 y=36
step 3: x=12 y=24
step 4: x=12 y=12
gcd = 12 after 4 steps

Reading it. Each step replaces the larger number by the difference; the gcd does not change (any common divisor of xx and yy divides x−yx - y, and conversely), so when x=yx = y the common value is the gcd: 12. With a while (x != y) loop and x=yx = y at the start, the body would not run and the answer would be xx at once. With the do-while form and x=y=5x = y = 5 the body would run once (y=5−5=0y = 5 - 5 = 0), after which x≠yx \ne y and the if branch (x = x - y with y=0y = 0) subtracts 0 for ever: an endless loop. Check which loop form a question uses before trusting a quick answer.

EX 3switch and fall-through

Medium
#include <stdio.h>
 
static void classify(int c) {
    printf("c=%d:", c);
    switch (c) {
    case 1:
        printf(" one");
        /* fall through */
    case 2:
        printf(" two");
        break;
    case 3:
    case 4:
        printf(" three-or-four");
        /* fall through */
    default:
        printf(" other");
    }
    printf("\n");
}
 
int main(void) {
    int inputs[6] = {1, 2, 3, 4, 0, 9};
    for (int k = 0; k < 6; k++) classify(inputs[k]);
    return 0;
}
c=1: one two
c=2: two
c=3: three-or-four other
c=4: three-or-four other
c=0: other
c=9: other

Reading it. For c = 1 the code of case 1 runs, has no break, and falls through into case 2: "one two". For c = 2 only "two". The labels case 3: and case 4: together share the statements after case 4:, which print "three-or-four" and fall through into default: "three-or-four other" for both 3 and 4. For 0 and 9 no label matches and control goes to default: "other". The rule to apply: find the entry point, then run forward until a break.

EX 4Short-circuit evaluation and side effects

Medium
#include <stdio.h>
 
static int f(int v) {
    printf("f(%d) ", v);
    return v;
}
 
int main(void) {
    int r, i = 0, count = 0;
    r = f(0) && f(1);
    printf("-> %d\n", r);
    r = f(1) && f(2);
    printf("-> %d\n", r);
    r = f(1) || f(0);
    printf("-> %d\n", r);
    r = f(0) || f(3);
    printf("-> %d\n", r);
    for (int j = -2; j <= 2; j++)
        if (j > 0 && i++) count += j;
    printf("i=%d count=%d\n", i, count);
    return 0;
}
f(0) -> 0
f(1) f(2) -> 1
f(1) -> 1
f(0) f(3) -> 1
i=2 count=2

Reading it. f(0) && f(1) stops after f(0) (false): f(1) is never called, which the output shows. f(1) || f(0) stops after f(1) (true). f(1) && f(2) and f(0) || f(3) must evaluate both. In the loop, j > 0 && i++ evaluates i++ only for j=1j = 1 and j=2j = 2: at j=1j = 1 the old value of i (0) is the result, so nothing is added, and i becomes 1; at j=2j = 2 the old value 1 is true: count += 2, and i becomes 2. A side effect on the right of && or || is conditional: do not count it unless the left operand lets it run.

EX 5How many times is printf executed?

Medium

A mixture of integer and floating-point arithmetic, a prefix decrement, a compound assignment and a switch with fall-through inside a loop. The counter shown counts the calls of say.

#include <stdio.h>
 
static int shown;
 
static void say(int v) {
    printf(" %d", v);
    shown++;
}
 
int main(void) {
    int j = 5 / 2 + 7 / 2.0 + 3 / 4;        /* 2 + 3.5 + 0 = 5.5 is converted to int: 5 */
    int k = 4;
    printf("j = %d\n", j);
    k -= --j;                                /* j becomes 4, then k = 4 - 4 */
    printf("j = %d, k = %d\n", j, k);
    for (int i = 0; i < 5; i++) {
        printf("i = %d, i + k = %d:", i, i + k);
        switch (i + k) {
        case 0:
        case 1:
            say(i + k);
            /* fall through */
        case 2:
            say(i + k);
            break;
        case 3:
            say(i + k);
            /* fall through */
        default:
            say(i + k);
        }
        printf("\n");
    }
    printf("printf was executed %d times by say\n", shown);
    return 0;
}
j = 5
j = 4, k = 0
i = 0, i + k = 0: 0 0
i = 1, i + k = 1: 1 1
i = 2, i + k = 2: 2
i = 3, i + k = 3: 3 3
i = 4, i + k = 4: 4
printf was executed 8 times by say

Reading it. The expression 5 / 2 + 7 / 2.0 + 3 / 4 is 2+3.5+0=5.52 + 3.5 + 0 = 5.5 (the divisions of two integers truncate, the one with 2.0 is floating point), and assigning 5.55.5 to an int truncates to 5. k -= --j first decrements j (to 4) and then subtracts it: k=4−4=0k = 4 - 4 = 0. The loop then switches on 0, 1, 2, 3, 4: 0 and 1 enter at case 0/case 1, print, fall into case 2, print and break (two prints each); 2 enters case 2, prints once and breaks; 3 prints in case 3 and falls into default (two prints); 4 goes to default (one print). Total 2+2+1+2+1=82 + 2 + 1 + 2 + 1 = 8. Write the value of the switch expression for each iteration, find the entry label, and add the statements until the break.

EX 6Iteration counts

GATE level
#include <stdio.h>
 
int main(void) {
    int n = 10, m = 100, c, i, j;
    c = 0; for (i = 0; i < n; i++) c++;
    printf("for (i = 0; i < n; i++), n = 10 | %d | n\n", c);
    c = 0; for (i = 0; i < n; i += 3) c++;
    printf("for (i = 0; i < n; i += 3), n = 10 | %d | ceil(n/3) = %d\n", c, (n + 2) / 3);
    c = 0; for (i = 1; i < m; i *= 2) c++;
    printf("for (i = 1; i < m; i *= 2), m = 100 | %d | ceil(log2 m) = 7\n", c);
    c = 0; for (i = m; i > 1; i /= 2) c++;
    printf("for (i = m; i > 1; i /= 2), m = 100 | %d | floor(log2 m) = 6\n", c);
    c = 0; for (i = 0; i < n; i++) for (j = 0; j < i; j++) c++;
    printf("for i < n: for (j = 0; j < i; j++), n = 10 | %d | n(n-1)/2 = %d\n", c, n * (n - 1) / 2);
    c = 0; for (i = 0; i < n; i++) for (j = i; j < n; j++) c++;
    printf("for i < n: for (j = i; j < n; j++), n = 10 | %d | n(n+1)/2 = %d\n", c, n * (n + 1) / 2);
    c = 0; for (i = 0; i < n; i++) for (j = 0; j < m; j++) c++;
    printf("for i < n: for j < m, n = 10, m = 100 | %d | n * m\n", c);
    c = 0; i = 0; do { c++; } while (i > 0);
    printf("do { } while (i > 0), i = 0 | %d | a do-while runs once before it tests\n", c);
    c = 0; i = 0; while (i > 0) c++;
    printf("while (i > 0), i = 0 | %d | a while may not run at all\n", c);
    return 0;
}
for (i = 0; i < n; i++), n = 10 | 10 | n
for (i = 0; i < n; i += 3), n = 10 | 4 | ceil(n/3) = 4
for (i = 1; i < m; i *= 2), m = 100 | 7 | ceil(log2 m) = 7
for (i = m; i > 1; i /= 2), m = 100 | 6 | floor(log2 m) = 6
for i < n: for (j = 0; j < i; j++), n = 10 | 45 | n(n-1)/2 = 45
for i < n: for (j = i; j < n; j++), n = 10 | 55 | n(n+1)/2 = 55
for i < n: for j < m, n = 10, m = 100 | 1000 | n * m
do { } while (i > 0), i = 0 | 1 | a do-while runs once before it tests
while (i > 0), i = 0 | 0 | a while may not run at all

Reading it. The loop i += 3 over 0,3,6,90, 3, 6, 9 runs ⌈10/3⌉=4\lceil 10/3 \rceil = 4 times. The doubling loop 1,2,4,…,641, 2, 4, \ldots, 64 runs 7 times for m=100m = 100 (27=128≥1002^7 = 128 \ge 100); the halving loop 100,50,25,12,6,3100, 50, 25, 12, 6, 3 runs 6 times (and stops when i=1i = 1). The first nested loop sums 0+1+⋯+9=450 + 1 + \cdots + 9 = 45, the second 10+9+⋯+1=5510 + 9 + \cdots + 1 = 55; independent bounds multiply: 10×100=100010 \times 100 = 1000. A do-while with a false condition still runs once; a while with a false condition runs zero times.

EX 7The two classic traps

GATE level

An assignment = where a comparison was meant is legal and its value is the assigned value, so if (x = 5) is always true (and sets x); and an else binds to the nearest if, whatever the indentation says. The compiler warns about both.

#include <stdio.h>
 
int main(void) {
    int x = 0, a = 1, b = 0;
    if (x = 5) printf("assignment in the condition: taken, x is now %d\n", x);
    if (a)
        if (b)
            printf("inner if taken\n");
    else
        printf("the else belongs to the NEAREST if (the one with b), not to the one with a\n");
    return 0;
}
assignment in the condition: taken, x is now 5
the else belongs to the NEAREST if (the one with b), not to the one with a

Reading it. if (x = 5) assigns 5 to x and the value of the assignment, 5, is true: the message is printed and x is changed (a comparison would be x == 5). In the nested if, the indentation suggests that the else belongs to if (a), but it belongs to if (b), the nearest one: since a is 1 and b is 0, the inner if fails and the else of the inner if runs. Braces around the inner if would attach the else to the outer one.

Cheat box

Cheat box

  • Condition: 0 is false, anything else true. = assigns, == compares.
  • while: test first. do-while: body first (at least once). for: init, test, body, update.
  • break leaves the innermost loop or switch; continue goes to the update (for) or the test.
  • switch: jump to the matching label (or default), then fall through until break.
  • && and || skip the right operand when the left decides; its side effects do not happen.
  • else goes with the nearest if.
  • Counts: step cc: ⌈n/c⌉\lceil n/c \rceil; doubling: ⌈log⁡2m⌉\lceil \log_2 m \rceil; halving: ⌊log⁡2m⌋\lfloor \log_2 m \rfloor; dependent nested loops sum, independent multiply.

Traps and GATE patterns

Connections

Evaluation order inside one condition (i++ && i++) is the subject of sequence points and undefined behaviour; && is the one operator with a guaranteed order. A loop is the iterative twin of recursion; counting its iterations is the first step of analysing an algorithm; and the compiler translates every loop and switch into tests and jumps (control flow translation). Functions that contain loops are in functions and parameter passing.

PYQs

6 previous year questions from your book. I re-solved each one myself (5 by running or simulating, 1 by reasoning only); the book's key is shown next to my answer. All PYQs

GATE 2025 · Set 1 · NAT · 2 marksQ1 · page 10 of the book
#include < stdio.h >
int gate(int n) {
    int d, t, newnum, turn;
    newnum = turn = 0; t=1;
    while(n >= t) t *= 10;
    t /= 10;
    while(t > 0) {
        d = n / t;
        n = n % t;
        t /= 10;
        if(turn) newnum = 10 * newnum + d;
        turn = (turn + 1) % 2;
    }
    return newnum;
}
int main () {
    printf("%d", gate(14362));
    return 0;
}

The value printed by the given C program is ________  .
(Answer in integer)
GATE 2025Q2 · page 10 of the book
int x=126,y=105;

  do {
            if(x>y) x=x-y;
        else y=y-x;
            } while(x!=y);

printf("%d",x);

The output of the given C code segment is________  .
(Answer in integer)
GATE 2021 · Set 2 · MCQQ3 · page 10 of the book
Consider the following ANSI C code segment:
z = x + 3 + y->f1 + y→f2;
  for (i = 0; i< 200; i = i + 2)
{
    if (z >i) {
      p = p + x + 3:
      q = q + y→f2;
    } else {
      p = p + y→f2:
      q = q + x + 3:
    }
}
Assume that the variable y points to a struct (allocated
on the heap) containing two fields f1 and f2, and the
local variables x, y, z, p, q, and i are allotted registers.
Common
sub-expression
elimination
(CSE)
optimization is applied on the code. The number of
addition and dereference operations (of the form y->f1
or y->f2) in the optimized code, respectively, are:
  • (a)303 and 102
  • (b)303 and 2
  • (c)403 and 102
  • (d)203 and 2
GATE 2021 · Set 1 · MCQ · 2 marksQ4 · page 10 of the book
Consider the following ANSI C program.
  #include <stdio.h>
   int main()
{
int i, j, count;
count = 0;
i = 0;
for (j = –3, j <= 3; j++)

{
 if ((j >= 0) && (i++))
 count = count + j;

}
count = count + i;
printf("%d", count);
   return 0;
}

Which of one of the following options is correct?
  • (a)The program will compile successfully and output 10 when executed.
  • (b)The program will not compile successfully.
  • (b)The program will compile successfully and output 8 when executed.
  • (d)The program will compile successfully and output 13 when executed.
year not read yetQ10 · page 12 of the book
Consider the following C program:
# include <stdio.h>
int main( )
{
int i, j, k = 0;
j = 2 * 3 / 4 + 2.0 / 5 + 8 / 5;
k  - = --j;
for (i = 0; i< 5; i++)
{
switch(i + k)
{
case 1:
case 2: printf("\n%d", i + k);
case 3: printf("\n%d", i + k);
default: printf("\n%d", i + k);

 }
 }
return 0;
}
Total number of times printf() executed ?
GATE 2012 · MCQQ14 · page 13 of the book
What will be the output of the following C program
segment?

char inchar = 'A';
  switch (inchar)
{
case 'A' :
printf ("choice A ") ;
case 'B' :
printf ("choice B ") ;
case 'C' :
case 'D' :
case 'E' :
default:
printf ("No Choice") ;
}
  • (a)No Choice
  • (b)Choice A
  • (c)Choice A Choice B No Choice
  • (d)Program gives no output as it is erroneou

Self-check

Question 1

int x = 3; do { x--; } while (x > 5); How many times does the body run, and what is x?

Show answer

Once (a do-while runs its body before testing); x=2x = 2.

Question 2

switch (2) { case 1: printf("a"); case 2: printf("b"); case 3: printf("c"); break; default: printf("d"); } prints?

Show answer

"bc": enter at case 2, fall into case 3, break.

Question 3

int i = 0; if (i++ && i++) ; printf("%d", i); prints?

Show answer

1: i++ yields 0 (false) and increments i to 1; the right operand is not evaluated.

Question 4

How many times does for (i = 1; i <= 100; i *= 3) body run?

Show answer

i=1,3,9,27,81i = 1, 3, 9, 27, 81: 5 times (the next, 243, is above 100).

Question 5

for (i = 0; i < 4; i++) for (j = i; j < 4; j++) count++; ends with count?

Show answer

4+3+2+1=104 + 3 + 2 + 1 = 10.

Revision card

One-screen revision

  • 0 false, non-zero true. while tests first, do-while runs once, for has init, test, update.
  • break: innermost loop or switch. continue: next iteration (the update in a for).
  • switch: entry at the matching label, falls through until break; default when nothing matches.
  • &&, || skip the right operand; side effects too. else goes to the nearest if.
  • Iteration counts: ⌈n/c⌉\lceil n/c \rceil, ⌈log⁡2m⌉\lceil \log_2 m \rceil, ⌊log⁡2m⌋\lfloor \log_2 m \rfloor, sums and products for nested loops.

References

  • ·Kernighan, Ritchie, The C Programming Language (2nd edition), Chapter 3 Control Flow
  • ·King, C Programming: A Modern Approach (2nd edition), Chapters 5 Selection Statements and 6 Loops
  • ·Forouzan, Gilberg, Computer Science: A Structured Programming Approach Using C, Chapters 5 and 6 (selection and repetition)

Verification

Every program on the page is compiled and run by npm run verify:c (the two trap programs with their compiler warnings allowed, as marked), and the tables are the output of the same programs run by scripts/gen-pds-control-traces.py (the sources are shared with scripts/pds_control.py, and scripts/enum-checks/pds_control.py asserts that the page prints exactly those sources). The same check recomputes every output with a model written in Python, compiles a batch program that runs the digit loop for every n up to 5000, Euclid's subtraction loop for every pair up to 60, the switch for every value from -50 to 50 and the loop trip counts for n up to 200, and compares them with Python, so the formulas for the number of iterations are confirmed on the whole range. tests/pds-control-traces.test.ts recomputes the tables in TypeScript. The behaviour shown (short-circuit, fall-through, the else binding to the nearest if, assignment in a condition) is defined by the C standard; the order in which the arguments of one call are evaluated is NOT defined and the programs never depend on it. Textbook chapter titles are from memory. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand (long C programs were not re-read line by line: they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose). One wrong word fixed (in the endless-loop example the branch that subtracts 0 is the if branch, not the else branch). Status raised to self-checked; verified needs a textbook or human check.

last verified: never