Notifications

No notifications

/Phase 1

Control Flow (if / else / switch)

Making Decisions 🛣️

So far our programs run top to bottom. Real programs need to choose what to do based on data. That's control flow.

C gives you four main tools:

ToolWhen to use
if / else if / elseA small number of conditions
switch / caseMany discrete values of one variable
Ternary ?:A simple value choice (one line)
gotoAlmost never (legacy)

if / else if / else

int marks = 78;

if (marks >= 90) { printf("Grade A\n"); } else if (marks >= 75) { printf("Grade B\n"); } else if (marks >= 60) { printf("Grade C\n"); } else { printf("Try again\n"); }

Rules:

  • The condition goes inside ( ).
  • The body goes inside { } (braces are technically optional for one statement, but always use them — saves bugs).
  • C treats 0 as false and anything else as true.

switch / case

When you're checking ONE variable against many constant values:

int day = 3;
switch (day) {
    case 1: printf("Monday");    break;
    case 2: printf("Tuesday");   break;
    case 3: printf("Wednesday"); break;
    case 4: printf("Thursday");  break;
    case 5: printf("Friday");    break;
    default: printf("Weekend");
}

> ⚠️ Don't forget break; — without it, execution falls through to the next case.

Ternary — one-line if/else

int max = (a > b) ? a : b;
printf("%s\n", (n % 2 == 0) ? "even" : "odd");

Truthiness

Anything non-zero is true:

int n = 5;
if (n)          { /* true  */ }
if (!n)         { /* false */ }
char *s = NULL;
if (s)          { /* false (NULL == 0) */ }

On this page

Detailed Theory

Control flow is what turns a list of instructions into a program. Without if, your code can do exactly one thing. With it, your code can react to anything.

Boolean Values in C — There Aren't Any (Until C99)

Original C had no bool type. It used int:

  • 0 is false
  • Anything else is true (yes, even -1)
Since C99 you can use:

#include <stdbool.h>

bool isReady = true; if (isReady) { ... }

Under the hood, bool is just a tiny integer. The header is pure sugar.

Always Use Braces

C lets you skip braces for a single statement:

if (x > 0)
    printf("positive\n");

That works — but it has caused billions of dollars of bugs. The infamous Apple "goto fail" bug came from this. Just always use braces:

if (x > 0) {
    printf("positive\n");
}

It's two extra characters and it removes a whole class of bugs.

The Dangling-else Problem

Without braces, an else binds to the nearest if:

if (a)
    if (b)
        do_x();
    else
        do_y();   // belongs to "if (b)", NOT "if (a)" — confusing!

Braces fix it:

if (a) {
    if (b) do_x();
    else   do_y();
}

Chained if/else if vs Many ifs

// ❌ Three independent checks — all run
if (score >= 90) printf("A");
if (score >= 75) printf("B");   // ALSO runs if score = 95!
if (score >= 60) printf("C");

// ✅ Chained — only ONE branch runs if (score >= 90) printf("A"); else if (score >= 75) printf("B"); else if (score >= 60) printf("C"); else printf("F");

The chained version is faster (early exit) and almost always what you want.

switch — Power and Pitfalls

switch (expression) {
    case constant1:
        // code
        break;
    case constant2:
        // code
        break;
    default:
        // code
}

Rules: 1. expression must be an integer-like type (int, char, enum). Cannot use strings or floats. 2. case labels must be constants known at compile time. 3. break exits the whole switch. Forget it and you fall through. 4. default is optional but recommended — handles unexpected values.

Intentional fall-through

Sometimes fall-through is what you want — group cases together:

switch (ch) {
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u':
        printf("vowel\n");
        break;
    default:
        printf("consonant\n");
}

When if vs switch

Use switch whenUse if when
Comparing one variable to many constantsConditions involve ranges (x > 5)
All cases are integer constantsConditions involve different variables
You want compiler optimization (jump table)Conditions involve floats / strings

The goto Statement

C still has goto. Don't use it for control flow. The only legitimate modern use is breaking out of nested loops on error, common in kernel code:

for (...) {
    for (...) {
        if (error) goto cleanup;
    }
}
cleanup:
    free(buf);

For everything else, goto makes code unreadable. Avoid it.

Common Mistakes Cheat Sheet

MistakeBug
if (x = 5)Assignment, always true
Missing break; in switchFalls through to next case
switch (3.14)Compile error — switch needs int-like
if (a < b < c)Doesn't mean what you think — compares (a
Comparing strings with ==Compares pointers, not text — use strcmp

Master if/else and switch and you can express any algorithm in C.