🌱 C Basics
Comparisons & logic: how C decides
▶ Open the interactive lesson — free, no signupOne missing character — typing = where you meant == — can turn a password check into one that always says yes. Comparisons are how programs decide anything at all, and by the end of this lesson you'll recognize that one-character bug on sight and know how to make the compiler catch it for you.
Every decision a program makes — checking a password, deciding whether to keep going — boils down to a comparison. C's comparison operators are == != < > <= >=, and here's the twist: they don't produce some special true/false type of value. They return a plain int — 1 for true, 0 for false.
#include <stdio.h>
int main(void) {
int x = 7, y = 10;
printf("x == y : %d\n", x == y);
printf("x != y : %d\n", x != y);
printf("x < y : %d\n", x < y);
printf("x >= y : %d\n", x >= y);
int adult = 1, has_ticket = 0;
printf("adult && has_ticket : %d\n", adult && has_ticket);
printf("adult || has_ticket : %d\n", adult || has_ticket);
printf("!has_ticket : %d\n", !has_ticket);
return 0;
}$ gcc compare.c -o compare && ./compare x == y : 0 x != y : 1 x < y : 1 x >= y : 0 adult && has_ticket : 0 adult || has_ticket : 1 !has_ticket : 1
Truthiness: zero is false, everything else is true
Going the other way, wherever C expects a condition, it applies one rule: 0 means false; any nonzero value means true. -3 is true. 0.5 is true. 'A' (which is 65) is true. This simple rule powers idioms you'll see everywhere, like if (count) meaning "if count isn't zero".
🧠 Checkpoint: In a C condition, which of these values counts as TRUE?
00.0-1'\0'
Show answer
-1 — The rule is brutally simple: zero (in any type) is false, everything else is true. −1 is nonzero, so it’s true. '\0' is the character with value 0 — false.
The bug that launched a thousand debugging sessions: = vs ==
int logged_in = 0;
/* meant to check, actually assigns! */
if (logged_in = 1) {
printf("Welcome back, admin!\n"); /* runs EVERY time */
}= assigns, == compares — and both are valid in a condition. if (x = 0) assigns 0 to x, and the assignment's value (0) makes the condition false — always. if (x = 5) is always true. No error, just silently wrong logic. Compile with -Wall (GCC suggests extra parens when you really mean assignment) and this bug can't hide.
Combining conditions: &&, ||, !
a && b— true if both are true (logical AND)a || b— true if at least one is true (logical OR)!a— flips truth:!0is 1,!anything_elseis 0
And they hide a superpower: short-circuit evaluation. C evaluates left to right and stops as soon as the answer is known. If the left side of && is false, the right side is never evaluated at all. Watch calls in this trace — it counts how many times noisy() actually runs:
▶ This spot has an interactive trace widget — open the interactive lesson to play with it.
This isn't just an optimization — it's a guarantee you can lean on. The classic idiom if (n != 0 && total / n > 10) is safe: the division simply cannot happen when n is zero.
🧠 Checkpoint: In if (p != NULL && *p > 0), what happens when p is NULL?
- Crash — *p is still evaluated
- The whole condition is false; *p is never touched
- Compile error
- Undefined behavior
Show answer
The whole condition is false; *p is never touched — Short-circuit && guarantees left-to-right evaluation with an early exit: once p != NULL is false, the dereference on the right is skipped. This guard pattern is everywhere in real C.
The ternary operator: ?:
C's only three-operand operator is an if/else that fits inside an expression: condition ? value_if_true : value_if_false.
#include <stdio.h>
int main(void) {
int a = 12, b = 30;
int max = (a > b) ? a : b;
printf("max is %d\n", max);
printf("b is %s\n", (b % 2 == 0) ? "even" : "odd");
return 0;
}$ gcc ternary.c -o ternary && ./ternary max is 30 b is even
Ternaries shine for small choices — a max, a label, a sign. Nest them twice and readability dies. If it doesn't fit comfortably on one line, use a real if.
▶ This spot has an interactive editor widget — open the interactive lesson to play with it.
🧠 Checkpoint: What does x = (5 > 3) ? 10 : 20; assign?
- 10
- 20
- 1
- 5
Show answer
10 — 5 > 3 evaluates to 1 (true), so the ternary yields its first branch: 10. The second branch, 20, is not even evaluated.
Comparisons treat variables as whole values — but you can also reach inside them and flip individual bits. Next: the bitwise operators.
▶ Practice this lesson interactively (with live gcc)