Skip to content
Conditionals
step 1/5

Reading — step 1 of 5

Learn

~3 min readControl Flow

Conditionals

C's if looks like every language that copied it — which is all of them — but two of its original design choices are live ammunition: any number is a condition, and = fits where == belongs. Both compile silently. Both have specific defenses. Learn the defenses with the syntax.

The shape

if (score >= 90) {
    printf("A\n");
} else if (score >= 80) {
    printf("B\n");
} else {
    printf("F\n");
}

Parentheses around the condition: required. Braces: technically optional for single statements — write them anyway. The famous goto fail bug (Apple, 2014, TLS verification bypassed) was a brace-less if gaining an accidental second line. Every style guide since says the same thing: always brace.

Truthiness, C-style

C (pre-C99) didn't even have a bool type: zero is false, everything else is true. Comparisons return the int 1 or 0.

if (n)          /* means: if n != 0 */
if (!n)         /* means: if n == 0 */
if (strcmp(a, b) == 0)   /* strcmp returns 0 on EQUAL — write the == 0! */

Idiomatic C leans on this (if (ptr) for "pointer isn't NULL" is universal), but it's also why last lesson's strcmp trap bites: if (strcmp(a, b)) is true for different strings — reads like "if equal," means the opposite. House rule for clarity: bare truthiness for pointers and flags, explicit comparison (== 0, != 0) whenever a function's return value has meaning beyond yes/no.

The assignment-in-condition trap

if (x = 5) { … }     /* assigns 5 to x, then tests 5 → always true */
if (x == 5) { … }    /* what you meant */

One = missing, no error, condition always true — the single most storied bug in C. Defenses, in order of effectiveness: compile with -Wall (it warns on exactly this), and let your editor highlight it. Some veterans write "Yoda conditions" (if (5 == x)) so the typo'd version fails to compile; modern consensus is that warnings make that style unnecessary — but now you can read it in old code without blinking.

Logical operators and short-circuit

if (n > 0 && 100 / n > 5)     /* && stops if n <= 0 — division never runs */
if (a || b)                   /* || stops at the first true */

&& and || short-circuit: the right side only evaluates if needed. That's not trivia — it's a guard idiom: test-before-use in one line (ptr != NULL && ptr->value > 0), relied on by every C codebase alive. ! negates. Precedence tip that ends debugging sessions: && binds tighter than ||; parenthesize anything mixed.

C also has the ternary — grade = (score >= 60) ? 'P' : 'F'; — compact for simple picks, unreadable when nested; use accordingly.

Your exercise: FizzBuzz for one number

The eternal kata: multiple of 3 → Fizz, of 5 → Buzz, both → FizzBuzz, else the number itself. The trap is check order — test the "both" case first (n % 15 == 0), because a 3-then-5 chain classifies 15 as Fizz and stops. Chain: 15, then 3, then 5, then printf("%d\n", n). And since this is C: == in every condition, braces on every branch, -Wall mentally on. The kata is famous precisely because it's all edges and no algorithm — very on-brand for this language.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…