switch Statements

C · Lesson 11 of 32 6 min read Updated

When one variable can have many fixed values, such as a menu choice, a day number or a grade letter, a long else if chain becomes hard to read. The switch statement compares one value against a list of constants and jumps straight to the matching one.

In this lesson you will write switch statements, learn why break matters so much, group several values together, and mark deliberate fall-through with the C23 [[fallthrough]] attribute.

How switch works

A switch evaluates the expression in brackets once. It then jumps to the case label whose value matches. If nothing matches, it jumps to default, if there is one.

C
#include <stdio.h>

int main(void)
{
    int day = 3;

    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;
    default:
        printf("Weekend or invalid day\n");
        break;
    }
    return 0;
}
Output
Wednesday

The break statement ends the switch and continues after its closing brace. default is optional, but including it is good practice: it handles unexpected values, which are often the source of bugs. The break after default is not strictly needed, but it keeps every case looking the same and protects you if you add a new case below it later.

break and fall-through

A case label is only a starting point. Once C jumps to a label, it keeps running the statements below it, through any further labels, until it reaches a break or the end of the switch. This is called fall-through. Forget one break and you get a surprise:

C
#include <stdio.h>

int main(void)
{
    int floor_choice = 2;

    switch (floor_choice) {
    case 1:
        printf("Going to floor 1\n");
    case 2:
        printf("Going to floor 2\n");
    case 3:
        printf("Going to floor 3\n");
    default:
        printf("Doors closing\n");
    }
    return 0;
}
Output
Going to floor 2
Going to floor 3
Doors closing

The lift jumped to case 2 correctly but then fell through everything below it. With -Wextra, GCC warns "this statement may fall through" for each missing break, another reason to compile with warnings on.

Grouping cases

Fall-through is useful when several values need the same code. Stack the labels with nothing between them:

C
#include <stdio.h>

int main(void)
{
    char ch = 'e';

    switch (ch) {
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u':
        printf("%c is a vowel\n", ch);
        break;
    default:
        printf("%c is not a vowel\n", ch);
        break;
    }
    return 0;
}
Output
e is a vowel

Labels with no statements between them are never treated as a mistake, so the compiler does not warn here.

Intentional fall-through with [[fallthrough]]

Sometimes you really do want one case to run its own code and then continue into the next. Membership plans are a good example: a gold member gets everything a silver member gets, plus more.

C
#include <stdio.h>

int main(void)
{
    char plan = 'S';   // G = gold, S = silver, B = basic

    printf("Benefits of plan %c:\n", plan);
    switch (plan) {
    case 'G':
        printf("- Free home delivery\n");
        [[fallthrough]];
    case 'S':
        printf("- 10%% off every order\n");
        [[fallthrough]];
    case 'B':
        printf("- Monthly offers by SMS\n");
        break;
    default:
        printf("- Unknown plan\n");
        break;
    }
    return 0;
}
Output
Benefits of plan S:
- 10% off every order
- Monthly offers by SMS

A silver member enters at case 'S' and falls into case 'B'. Change plan to 'G' and all three benefits print.

A menu-driven calculator

switch works naturally with char values such as operator symbols. A case can contain any statements, including an if:

C
#include <stdio.h>

int main(void)
{
    double a = 84.0, b = 12.0;
    char op = '/';
    double result = 0.0;
    bool ok = true;

    switch (op) {
    case '+': result = a + b; break;
    case '-': result = a - b; break;
    case '*': result = a * b; break;
    case '/':
        if (b != 0) {
            result = a / b;
        } else {
            ok = false;
        }
        break;
    default:
        ok = false;
        break;
    }

    if (ok) {
        printf("%.2f %c %.2f = %.2f\n", a, op, b, result);
    } else {
        printf("Cannot calculate\n");
    }
    return 0;
}
Output
84.00 / 12.00 = 7.00

Short cases may sit on one line, as the first three do. The default branch rejects any operator the program does not know.

Rules for case labels

  • The switch expression must be an integer type: int, char, long, bool or an enum. You cannot switch on a double or a string.
  • Each case value must be an integer constant expression, known at compile time: a literal such as 3 or 'a', a #define macro, an enum constant, or a C23 constexpr value. A const int variable or a normal variable is not allowed.
  • Two cases cannot have the same value; the compiler reports a duplicate case.
  • Ranges such as case 1 ... 5: are a GCC extension, not standard C. Use stacked labels or an if instead.
  • If a case needs its own local variables, wrap its statements in braces: case 1: { int bonus = 50; ... break; }. This keeps the variable's scope inside that case.

switch or if-else?

SituationBetter choice
One variable compared with many fixed valuesswitch
Ranges, such as marks from 75 to 89if...else if
Strings, decimals or several different variablesif...else if
Several values sharing the same codeswitch with stacked labels

Common mistakes

  • Forgetting break. The code falls into the next case. Compile with -Wextra to get a warning.
  • Switching on a string. switch (city) with case "Pune": does not compile. Compare strings with strcmp and if.
  • Using a variable as a label. case limit: fails unless limit is a compile-time constant such as a constexpr value.
  • No default. Unexpected values silently do nothing, which hides bugs.

Key points

  • switch jumps to the case matching an integer value, or to default when none matches.
  • Execution continues through later cases until a break; this is called fall-through.
  • Stack labels with nothing between them to share code between values.
  • Mark deliberate fall-through with C23 [[fallthrough]]; to document it and silence the warning.
  • Case labels must be integer constants: literals, macros, enum values or constexpr values.

Exercise

A college canteen in Kochi numbers its items: 1 for tea (Rs 12), 2 for coffee (Rs 15), 3 for veg puff (Rs 20) and 4 for meals (Rs 60). Write a program with int choice = 3; and int quantity = 4; that uses a switch to find the item name and price, then prints the bill. For any other choice, print "Invalid choice".

Show solution
C
#include <stdio.h>

int main(void)
{
    int choice = 3;
    int quantity = 4;
    int price = 0;

    switch (choice) {
    case 1:
        printf("Tea");
        price = 12;
        break;
    case 2:
        printf("Coffee");
        price = 15;
        break;
    case 3:
        printf("Veg puff");
        price = 20;
        break;
    case 4:
        printf("Meals");
        price = 60;
        break;
    default:
        printf("Invalid choice\n");
        return 1;
    }
    printf(" x %d = Rs %d\n", quantity, price * quantity);
    return 0;
}
Output
Veg puff x 4 = Rs 80

Each case prints the item name and sets the price, then break leaves the switch. The default case returns early, so the bill line runs only for valid choices.

Quick Quiz

1. What happens if a case has no break?

2. Which of these can be used as a case label?

3. What does [[fallthrough]]; do in C23?

4. When is an if...else if chain better than a switch?

Learn C with a mentor

Free lessons get you started. Our Java, C & C++ Programming training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call