Control Flow
if/else, switch/case/fallthrough, while, do-while, for, break/continue, nested loops, goto.
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