Foundations · Module 1 · Lesson 1 of 7
Making Decisions: if, else if, and else
Learn how to branch program flow with if, else if, and else, use comparison and logical operators, and trace conditional execution step by step.
By the end you can
- Write if, else if, and else statements to branch program flow
- Use comparison operators (==, !=, <, >, <=, >=) in conditions
- Combine conditions with logical operators (&&, ||, !)
- Trace conditional execution through a trace
01 · A question first
Your program asks the user for their age. If they are 18 or older, print "Adult". Otherwise print "Minor". But what if they are exactly 18? What if they are 65 or older and should get a senior discount? How does the computer choose which path to take, and what happens when two conditions could both be true?
Make a guess, then step through the trace below to check it.
02 · Watch it run
int age = 25;if (age >= 65) { printf("Senior\n");} else if (age >= 18) { printf("Adult\n");} else { printf("Minor\n");}- slot 0age: 25(looked at in this step)
- slot 1condition1: false
- slot 2condition2: unchecked
- slot 3output: none
Variable age is set to 25. The first condition (age >= 65) is checked.
Machine work: compare 25 >= 65 -> false
03 · The idea
Start with the problem
Every program you have written so far executes in a straight line from top to bottom: line 1 runs, then line 2, then line 3, until main returns 0. That works for a simple calculator formula, but real programs must react differently depending on the data they receive.
Suppose you are writing a grading program that reads a student's exam score (0 to 100) and prints a letter grade:
90or above prints"Grade: A"80to89prints"Grade: B"70to79prints"Grade: C"- Below
70prints"Grade: F"
Without a way to choose between paths, your program would print all four grades every time it ran. Choosing which statements to execute and which to skip based on a runtime value is called branching or conditional control flow, and the fundamental tool for it in C is the if statement.
How the idea works
An if statement evaluates a condition inside parentheses (...). If the condition is true, the block of statements inside the curly braces \{...\} executes. If the condition is false, the CPU jumps right past the closing brace without running a single line inside the block.
In the trace above, age starts at 25. In step 1, the CPU evaluates the first condition age >= 65. Because 25 >= 65 is false, the program skips the "Senior " block completely and moves to the else if (age >= 18) test on line 3. In step 2, 25 >= 18 evaluates to true, so step 3 runs printf("Adult "); and then jumps past the trailing else block to finish the chain.
How C represents true and false
Unlike languages that were designed with a separate boolean type from day one, C represents truth values as plain integers:
0means false.- Any non-zero integer (
1,42,-7) means true.
When you write a comparison using one of C's six relational operators, the operator compares the two numbers and produces the integer 1 if the relationship holds, or 0 if it does not:
| Operator | Meaning | Example (a = 5, b = 3) | Evaluated integer result |
|---|---|---|---|
== | Equal to | a == b | 0 (false) |
!= | Not equal to | a != b | 1 (true) |
< | Strictly less than | a < b | 0 (false) |
> | Strictly greater than | a > b | 1 (true) |
<= | Less than or equal to | a <= b | 0 (false) |
>= | Greater than or equal to | a >= b | 1 (true) |
Modern C (since C99) also provides <stdbool.h>, which defines the type bool and the constants true (1) and false (0), but under the hood every if (...) test simply checks whether the expression inside the parentheses is non-zero.
Choosing between two paths with else
When you need one action if a condition holds and a fallback action whenever it does not, attach an else block:
if (age >= 18) {
printf("Adult");
} else {
printf("Minor");
}The if branch and the else branch are mutually exclusive and exhaustive: for any value of age, the CPU is guaranteed to execute one branch and skip the other.
Chaining multiple conditions with else if
When a decision has three or more outcomes, chain tests together with else if:
#include <stdio.h>
int main(void) {
int score = 84;
if (score >= 90) {
printf("Grade: A");
} else if (score >= 80) {
printf("Grade: B");
} else if (score >= 70) {
printf("Grade: C");
} else {
printf("Grade: F");
}
return 0;
}Combining conditions with logical operators
Often a single decision depends on two or more facts at once—for example, checking that a score lies between 0 and 100. C provides three logical operators to combine conditions:
- Logical AND (
&&):cond1 && cond2is true (1) only when both conditions are true. - Logical OR (
||):cond1 || cond2is true (1) when at least one condition is true. - Logical NOT (
!):!condflips truth:!0becomes1, and!non_zerobecomes0.
if (score >= 0 && score <= 100) {
printf("Valid score");
}
if (day == 6 || day == 7) {
printf("Weekend");
}Why it is correct
Two rules make conditional chains predictable and safe:
- Top-down first-match execution: In an
if/else if/elseladder, conditions are tested strictly from top to bottom. The moment one condition evaluates to true, its block runs and every remaining branch in the chain is skipped, even if a later condition (score >= 70whenscoreis84) would also be true. That is why ordering matters: you must place the most restrictive condition (score >= 90, orage >= 65in the trace above) first. If you wroteif (age >= 18)beforeelse if (age >= 65), an age of70would matchage >= 18first and print"Adult", making the"Senior"branch dead code that can never run. - Short-circuit evaluation: Both
&&and||evaluate their left operand first and stop early if the overall answer is already decided. InA && B, ifAis false (0), the whole AND expression must be false, so C never evaluatesB. InA || B, ifAis true (1), the whole OR expression must be true, so C never evaluatesB. Programmers rely on short-circuiting every day to guard dangerous operations, such as checkingif (denom != 0 && numer / denom > 5)so the division never executes whendenomis zero.
What it costs
At the hardware level, an if statement compiles into two cheap CPU instructions: a comparison (cmp) that sets status flags in the processor, followed by a conditional jump (je, jne, jl, jge) that changes the instruction pointer if a branch is skipped.
Comparing two registers takes less than a nanosecond (1 CPU cycle). Modern processors also contain a branch predictor that guesses which path an if statement will take so the CPU can keep its pipeline full. When a branch is predictable, it costs almost nothing; when a branch flips randomly on every check, a misprediction flushes the CPU pipeline and costs roughly 15 to 20 cycles (~5 nanoseconds).
Pitfalls and variations
| Mistake | What goes wrong | Fix |
|---|---|---|
if (age = 18) | Assigns 18 to age and always evaluates to true (18 != 0) | Use the equality operator if (age == 18) |
Writing if (18 <= age <= 65) | C parses this as (18 <= age) <= 65, which compares 0 or 1 against 65 and is always true | Combine two comparisons with &&: if (age >= 18 && age <= 65) |
Omitting curly braces {} on multi-line bodies | Only the first statement after if (...) belongs to the branch; the second line runs unconditionally | Always wrap if and else bodies in {} braces |
Putting a semicolon right after if (x > 0); | The semicolon acts as an empty body, so the {...} block after it always runs | Never put a ; between if (...) and { |
Where it is used
Every piece of software relies on conditional branching: operating system kernels check whether a process has permission to open a file, network servers validate packet headers before parsing payloads, and financial engines verify account balances before authorizing transfers.
In the next lesson, you will combine conditions with loops (for and while) so your program can repeat work thousands of times without duplicating code.
04 · Prove it
Question 1 of 3 · answer from memory
If age is 70, which block executes in the trace above?
05 · Practice
Asked in interviews
Something wrong with this lesson? Report a problem