Control Flow: Selection (if, switch)
This chapter covers the two selection statements: if/else and switch. These are concise because the reader already knows them from other languages, but C has specific semantics worth pinning down.
Why This Matters
if and switch are straightforward, but switch has fall-through semantics and integer-only conditions that surprise programmers coming from languages with richer switch statements.
Prerequisites
c.core.8— expressions and evaluation.
Core Concept
if / else
if (condition)
statement;
else
statement;
condition is any scalar expression. It is true if nonzero, false if zero. Each branch is a *single statement*; use a block { } for multiple statements.
The else binds to the nearest unmatched if (the "dangling else" rule).
switch
switch (expression) {
case constant1:
statements;
break;
case constant2:
statements;
break;
default:
statements;
break;
}
The controlling expression must have integer type (after promotion). Each case label must be an integer constant expression. Execution jumps to the matching case and falls through subsequent cases unless a break (or return, goto) is reached.
Syntax
if (x > 0) {
/* ... */
} else if (x < 0) {
/* ... */
} else {
/* ... */
}
switch (x) {
case 0: /* ... */ break;
case 1:
case 2: /* shared handling for 1 and 2 */ break;
default: /* ... */ break;
}
Examples
Dangling else
if (a)
if (b)
f();
else
g(); /* binds to the inner if */
The else binds to the nearest unmatched if (if (b)). To bind it to the outer if, use braces.
switch fall-through
#include <stdio.h>
int main(void)
{
int x = 1;
switch (x) {
case 0: printf("zero\n"); break;
case 1: printf("one\n"); /* no break: falls through */
case 2: printf("one-or-two\n"); break;
default: printf("other\n");
}
return 0;
}
Expected output:
one
one-or-two
How It Works
if compiles to a conditional branch. switch compiles to either a chain of comparisons or a jump table (for dense, small integer case values), which can be faster. The compiler decides the strategy.
Variations
switch on expressions
The controlling expression can be any integer expression, not just a variable:
switch (get_status()) {
/* ... */
}
case ranges (non-standard extension)
GCC and Clang support case ranges as an extension (case 1 ... 5:), but this is not ISO C.
Common Mistakes
- Forgetting
breakin aswitchcase (unintended fall-through). - Declaring a variable directly after a
caselabel without braces (a label
cannot precede a declaration in older C; wrap in a block).
- Using a non-integer type as the
switchcontrolling expression. - Assuming
caselabels can be non-constant or duplicate (they cannot).
Undefined Behavior
- Falling off the end of a
switch(orif) does not by itself cause UB; the
statement simply completes. The controlling expression must be a valid integer expression (any UB in evaluating it propagates).
Portability
- Case ranges are a GCC/Clang extension, not ISO C.
- Jump-table vs. branch-chain is a compiler optimization detail.
Under the Hood
For dense case values, compilers emit a jump table (an array of target addresses indexed by the value). For sparse values, they emit a decision tree or a sequence of comparisons. This is an optimization detail, not a language feature.
Practical Usage
- Use
switchfor enumerating discrete integer states (e.g., enum-based state
machines).
- Group empty fall-through cases with a comment like
/* fall through */. - Prefer
if/else iffor range checks and non-integer conditions.
Exercises
1. Write a program that maps an integer day number (0–6) to a day name using switch, with a default for invalid input. 2. Demonstrate fall-through and then show how to avoid it. 3. Explain the dangling-else problem and write a corrected version.
Deep Challenge
Implement a small integer state machine using switch and an enum, with explicit fall-through where appropriate. Justify why switch (rather than a chain of ifs) is the better choice for this design.
Related Concepts
c.flow.for/c.flow.while— iteration.c.flow.jump— break, continue, goto.c.enum.decl— enums as switch labels.
References
- ISO/IEC 9899:2018 §6.8.4 (selection statements).
Verification
iftruthiness is nonzero/zero.VERIFIEDswitchcontrolling expression must be integer.VERIFIED- Fall-through semantics are standard.
VERIFIED - No example was executed during generation unless noted. `Execution not
verified.`
Progress
- [ ] Read
- [ ] Understand
- [ ] Complete examples
- [ ] Complete exercises
- [ ] Complete deep challenge
Concept checkboxes
- [ ] if/else
- [ ] switch/case/default
- [ ] Fall-through
- [ ] Dangling else
Mastery levels
| Concept | Current level (0–8) | Target level |
|---|---|---|
| c.flow.if | 0 | 5 |
| c.flow.switch | 0 | 5 |