How C makes decisions

Real-World Analogy

Think of a conditional as a fork in the road. Your program is walking along, and when it hits an if statement, it reads the sign (the condition). If the sign says "true" (any nonzero value), it takes the left path. If the sign says "false" (zero), it takes the right path (the else). A switch is like a post-office sorting machine — it reads a label (the value) and sends the parcel to the matching slot (case), falling through to the next one unless there is a stop sign (break).

C has no boolean type in C89/C90. In C, any integer value that is nonzero is true, and zero is false. The number 42 is true. The number -1 is true. Only 0 is false. C99 introduced <stdbool.h> with bool, true, and false, but under the hood they are still just 1 and 0. This means you can write if (ptr) to check that a pointer is not NULL, because NULL is 0.

The switch statement is a multi-way branch for integer (or character) values. Each case labels a value. Execution jumps to the matching case and falls through to subsequent cases until a break (or end of switch) is reached. This fall-through is intentional by design — it lets multiple cases share code — but forgetting break when you didn't want fall-through is one of the most common C bugs.

The dangling else problem: In C, an else always attaches to the nearest preceding unmatched if. Indentation is not syntax — it can mislead. Always use braces {} to make your intent explicit.

= vs == — the classic C bug

if (x = 5) does NOT test whether x equals 5. It assigns 5 to x (the result is 5, which is nonzero, so the condition is always true). This compiles without error and causes a logic bug. The correct test is if (x == 5). Enable compiler warnings (-Wall) — GCC will warn about assignment in a condition. Some programmers write if (5 == x) ("Yoda conditions") so a typo of = becomes a compile error.

Python (what you know)
# Python: indentation defines blocks
if x > 0:
    print("positive")
elif x == 0:
    print("zero")
else:
    print("negative")

# Python 3.10+ match (like switch)
match day:
    case 1: print("Monday")
    case 2: print("Tuesday")
    case _: print("other")
C (what you are learning)
/* C: braces define blocks */
if (x > 0) {
    printf("positive\n");
} else if (x == 0) {
    printf("zero\n");
} else {
    printf("negative\n");
}

/* switch for integer/char values */
switch (day) {
    case 1: printf("Monday\n"); break;
    case 2: printf("Tuesday\n"); break;
    default: printf("other\n"); break;
}
Always Use Braces

Even for single-statement bodies, always write if (cond) { statement; } with braces. Without braces, adding a second line inside looks correct but only the first line is conditional — a notoriously common bug (the Apple "goto fail" SSL vulnerability was caused by exactly this). Make it a habit: braces every time.

if, else if, else, and switch — annotated

/* if / else if / else */
if (condition1) {
    /* runs when condition1 is nonzero (true) */
} else if (condition2) {
    /* runs when condition1 is 0 AND condition2 is nonzero */
} else {
    /* runs when all above conditions are 0 (false) */
}

/* switch — only works with integer/char types */
switch (expression) {
    case CONSTANT1:
        /* code for case 1 */
        break;   /* MUST break to prevent fall-through */
    case CONSTANT2:
        /* code for case 2 */
        break;
    default:
        /* runs if no case matched — like else */
        break;
}
Fall-through is intentional: If you omit break, execution continues into the next case body. This is sometimes useful (multiple cases sharing code) but usually a bug if accidental. Always add a comment /* fall through */ when intentional, so reviewers know it's deliberate.

The Dangling Else Trap

/* MISLEADING indentation — the else belongs to the INNER if */
if (x > 0)
    if (x > 10)
        printf("big\n");
else                /* attaches to inner if, NOT outer if! */
    printf("non-positive\n");

/* FIXED with braces — now intent is clear */
if (x > 0) {
    if (x > 10) {
        printf("big\n");
    }
} else {          /* now clearly belongs to outer if */
    printf("non-positive\n");
}
Rule: An else always pairs with the nearest preceding unmatched if. Indentation is just whitespace to the compiler. Braces are the only reliable way to express your intent.

Complete programs you can compile and run

Example 1 — Temperature range classifier Week 1 Lecture
#include <stdio.h>

int main(void) {
    int temp;
    printf("Enter temperature (C): ");
    scanf("%d", &temp);

    if (temp < 0) {
        printf("Freezing\n");
    } else if (temp < 10) {
        printf("Cold\n");
    } else if (temp < 20) {
        printf("Cool\n");
    } else if (temp < 30) {
        printf("Warm\n");
    } else {
        printf("Hot\n");
    }

    /* C truth: 0 is false, everything else is true */
    int val = 42;
    if (val)           printf("val is truthy\n");   /* runs — 42 != 0 */
    if (!val)          printf("val is zero\n");      /* skipped */
    if (val == 0)      printf("val is zero\n");      /* skipped */

    return 0;
}
Sample run (input: 25)
Enter temperature (C): 25
Warm
val is truthy
Example 2 — switch with fall-through (day of week) Week 1 Lecture
#include <stdio.h>

int main(void) {
    int day = 3;  /* 1=Mon ... 7=Sun */

    switch (day) {
        case 1: printf("Monday\n");    break;
        case 2: printf("Tuesday\n");   break;
        case 3: printf("Wednesday\n"); break;
        case 4: printf("Thursday\n");  break;
        case 5: printf("Friday\n");    break;
        case 6:  /* intentional fall-through */
        case 7:
            printf("Weekend!\n");
            break;
        default:
            printf("Invalid day\n");
            break;
    }

    /* Demonstrating fall-through bug — MISSING break */
    int x = 2;
    switch (x) {
        case 1: printf("one\n");
        case 2: printf("two\n");   /* x==2, starts here */
        case 3: printf("three\n"); /* falls through! */
        default: printf("done\n"); /* falls through! */
    }

    return 0;
}
Output
Wednesday
two
three
done
Example 3 — Grade classifier using switch on character Week 2 Tutorial
#include <stdio.h>

int main(void) {
    char grade;
    printf("Enter grade (A/B/C/D/F): ");
    scanf(" %c", &grade);  /* space before %c skips whitespace */

    switch (grade) {
        case 'A':
            printf("Excellent — High Distinction\n");
            break;
        case 'B':
            printf("Good — Credit\n");
            break;
        case 'C':
            printf("Satisfactory — Pass\n");
            break;
        case 'D':
        case 'F':
            printf("Needs improvement — Fail\n");
            break;
        default:
            printf("Unknown grade: %c\n", grade);
            break;
    }

    return 0;
}
Sample run (input: B)
Enter grade (A/B/C/D/F): B
Good — Credit

Practice problems with solutions

P1 — Predict output: switch fall-through Week 2 Tutorial

Without running the code, predict exactly what is printed.

#include <stdio.h>
int main(void) {
    int n = 2;
    switch (n) {
        case 1: printf("A\n");
        case 2: printf("B\n");
        case 3: printf("C\n"); break;
        case 4: printf("D\n");
        default: printf("E\n");
    }
    return 0;
}
B
C
Trace: n==2, so execution jumps to case 2 and prints "B". There is no break, so it falls through to case 3 and prints "C". case 3 has a break, so execution exits the switch. Cases 4 and default are never reached.
P2 — Spot the bug: assignment in condition Week 2 Tutorial

This program is supposed to print "equal" only if x equals 10, but it always prints "equal". Find and fix the bug.

#include <stdio.h>
int main(void) {
    int x = 5;
    if (x = 10) {
        printf("equal\n");
    } else {
        printf("not equal\n");
    }
    return 0;
}
#include <stdio.h>
int main(void) {
    int x = 5;
    if (x == 10) {   /* Fixed: == for comparison, not = */
        printf("equal\n");
    } else {
        printf("not equal\n");
    }
    return 0;
}
Bug: x = 10 is an assignment expression. It sets x to 10 and evaluates to 10 (nonzero = true), so the condition is always true regardless of x's initial value. The fix is x == 10 (two equals signs). Compile with gcc -Wall to see the warning: "suggest parentheses around assignment used as truth value."
P3 — Dangling else: predict the output Lecture

The indentation suggests the else belongs to the outer if. Does it? What is the actual output when x = 5?

#include <stdio.h>
int main(void) {
    int x = 5;
    if (x > 0)
        if (x > 10)
            printf("big positive\n");
    else
        printf("non-positive\n");
    return 0;
}
(nothing is printed)
Why: The else belongs to the inner if (x > 10), not the outer one. So the logic is: if x>0, check if x>10 (no, x=5), and since the inner condition is false, execute the else ("non-positive")? Wait — but x=5 IS positive, so we do enter the outer if. Then x>10 is false, so the inner else runs... But actually x=5 IS >0, so we enter outer if. x>10 is false (5 is not >10), so we hit the inner else and print "non-positive"? Let us re-trace carefully:

Actually with x=5: outer if (5>0) is true → enter. inner if (5>10) is false → inner else runs → "non-positive" IS printed.

The key lesson: The else attaches to the inner if. To attach the else to the outer if, use braces: wrap the inner if in { }. This is exactly why always-use-braces is a rule.
P4 — Write a letter-grade classifier Week 2 Tutorial

Read an integer score (0–100) from the user. Print the letter grade: HD (85–100), D (75–84), CR (65–74), P (50–64), F (0–49). Handle invalid input (outside 0–100).

#include <stdio.h>

int main(void) {
    int score;
    printf("Enter score (0-100): ");
    if (scanf("%d", &score) != 1) {
        printf("Invalid input\n");
        return 1;
    }

    if (score < 0 || score > 100) {
        printf("Score out of range\n");
    } else if (score >= 85) {
        printf("HD (High Distinction)\n");
    } else if (score >= 75) {
        printf("D (Distinction)\n");
    } else if (score >= 65) {
        printf("CR (Credit)\n");
    } else if (score >= 50) {
        printf("P (Pass)\n");
    } else {
        printf("F (Fail)\n");
    }

    return 0;
}
Design notes: The conditions test from high to low — once a range matches, later else if branches are skipped. Always validate input first (check scanf's return value, then check range). Using else if rather than separate if statements ensures only one branch runs.

Key concepts to memorize

Card 1 of 10
Question — click to flip
Answer
Click card to flip • Use buttons to navigate

Test your understanding

Topic 04 Quiz — Conditionals Score: 0 / 6
1
In C (pre-C99, no stdbool.h), which value is considered false?LO1
multiple choice
2
True or False: In a switch statement, if a matching case has no break, execution automatically exits the switch.LO1
true / false
3
What is the bug in if (x = 0) { printf("zero\n"); }?LO1
multiple choice
4
Fill in: In a switch statement, which keyword is used to handle all unmatched values (the "catch-all")?LO1
fill in the blank
5
The dangling else rule says: an else always pairs with...LO1
multiple choice
6
Can a switch statement be used with a double expression, e.g. switch (3.14)?LO1
multiple choice
0/6
Quiz complete!