← Core SyntaxC PROGRAMMING 1.1.D

Control Flow

if/else, switch/case/fallthrough, while, do-while, for, break/continue, nested loops, goto.

StatusCollected
NotesChapter test: 4/4 (retry)

Nine pieces covering how execution actually branches and loops: if/else, switch, the three loop shapes, break/continue, nesting, and goto.

switch and fallthrough

switch (x) {
    case 1:
        do_one();
        break;
    case 2:
        do_two();
        // no break — falls through into case 3 on purpose
    case 3:
        do_three();
        break;
    default:
        do_default();
}

Forget a break and execution doesn't stop at the end of a case — it keeps running straight into the next one, including default. Sometimes that's intentional (case 2 falling into case 3 above); most of the time it's a bug waiting to be found the hard way.

The three loops

  • while (cond) { } — checks the condition before the first iteration; may run zero times.
  • do { } while (cond); — checks after the first iteration; always runs at least once.
  • for (init; cond; update) { } — all three clauses are optional, but the two semicolons never are. for (;;) is a valid infinite loop.

break, continue, and nesting

break exits the innermost loop or switch entirely; continue skips straight to the next iteration's condition check. Both only ever affect the loop or switch they're physically inside — there's no way to break out of two nested loops at once without a flag variable or a goto.

goto

int *buf1 = malloc(SIZE);
if (!buf1) goto fail;

int *buf2 = malloc(SIZE);
if (!buf2) goto fail_buf1;

/* ... use buf1 and buf2 ... */
free(buf2);
fail_buf1:
free(buf1);
fail:
return -1;

In application code goto is usually a smell. In C written for the kernel it's the standard way to unwind partial initialization on an error path without duplicating cleanup code at every possible failure point — jump forward, never backward, and only to labels later in the same function.

Notes from readers

Comments — via GitHub