Decision-making statements let your program choose different actions based on conditions. In C the primary decision statements are:
-
if -
if-else -
nested
if -
else if(ladder) -
switch-case
All conditions are expressions evaluated as true (nonzero) or false (zero).
1. if β single-branch decision
Definition: Evaluate a condition; if it is true, execute a statement or block; otherwise skip it.
Syntax:
or with a block:
Example:
Flow (ASCII):
Notes:
-
conditionis any expression; zero means false, nonzero true. -
Use braces
{}even for single statements to avoid bugs when adding lines later.
2. if-else β two-way decision
Definition: If condition is true execute first block; otherwise execute the else block.
Syntax:
Example (parity test):
Flow (ASCII):
Use-case: Choose between two mutually exclusive actions (e.g., valid vs invalid).
3. Nested if
Definition: Place an if (or if-else) inside another if or else to check additional conditions.
Example (age & permission):
When to use: When decisions are hierarchical (outer condition filters candidates for deeper checks).
Pitfall: Deep nesting makes code hard to readβrefactor into separate functions or use early returns to flatten.
4. else if ladder β multiple mutually exclusive tests
Definition: Chain multiple conditions; the first true branch runs; remaining branches are skipped.
Syntax:
Example (grading):
Flow (ASCII simplified):
Use-case: Ranges or ordered checks where only one branch should match (e.g., grading, status selection).
Best practice: Order conditions from most specific to least specific; ensure non-overlapping or intended priority.
5. switch-case β selecting based on discrete integral values
Definition: Multi-way branch that compares an integer expression against constant case labels. Useful when selecting among many discrete values.
Syntax:
Example (menu):
Key rules & notes:
-
exprmust be of an integral type (e.g.,int,char,enum) or a type that promotes to integral. Floating-point is not allowed. -
caselabels must be compile-time constant integer expressions. -
breakprevents fall-through to the next case. Withoutbreak, execution continues into the next case (deliberate fall-through is allowed but should be commented). -
defaultexecutes if no case matches; it's optional but recommended. -
You can group labels:
Flow (ASCII):
Use-cases: Menus, opcode/command dispatch, state machines, multi-value selection where values are discrete.
6. Practical examples (combined patterns)
Input validation + branch example
Switch with enum (good style)
7. Common pitfalls & gotchas
-
Assignment vs comparison:
if (x = 0)assigns 0 and tests false. Use==for comparison. Some preferif (0 == x)to cause compile error if=used accidentally. -
Missing braces:
if (cond) statement; statement2;β the second statement is always executed. Always use{}. -
Mixing
scanf& newline handling: Afterscanf("%d", &n), a newline remainsβbe careful when usingfgets()afterward. -
Switch fall-through: Forgetting
breakcauses accidental fall-through. If fall-through is intentional, comment/* fall through */. -
switch works on integers only: Do not attempt to
switchon strings; instead useif-elsechains or map strings to integer codes. -
Complex conditions unreadable: Long boolean expressions are error-prone; break into named boolean variables or functions.
8. Principles & best practices
-
Use braces
{}for everyif,else, andcasebody β prevents bugs and improves clarity. -
Prefer early returns (guard clauses) to reduce nested
ifdepth: -
Order
else iffrom most specific to least to ensure correct behavior. -
Prefer
switchfor many discrete values (cleaner and often faster than manyelse ifbranches). -
Use
enumfor meaningful case labels (improves readability and avoids magic numbers). -
Comment intentional fall-throughs in
switch. -
Check user input and handle default/invalid cases robustly.
-
Extract complex condition logic into well-named helper functions for readability and reuse.
-
Donβt put heavy computation or side effects in condition expressions; evaluate beforehand if needed.
-
Compile with warnings enabled (
-Wall -Wextra) to catch suspiciousif/switchcode.
9. When to use which
-
Use
if/if-elsefor simple true/false decisions or when testing ranges. -
Use nested
ifwhen one condition depends on a previous condition being true. -
Use
else ifladder for ordered conditions or range tests (e.g., grading). -
Use
switchwhen you need to branch on many fixed discrete values (e.g., menu/options, protocol opcodes, enum states).
10. Quick checklist before committing decision code
-
Are conditions clear and simple?
-
Are braces present for all blocks?
-
Are early exits used to avoid deep nesting?
-
For
switch: arecaselabels constant andbreakpresent? Isdefaulthandled? -
Is input validated before use in conditions?
-
Do you avoid mixing side effects inside condition expressions?