Reading — step 1 of 5
Learn
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…