ZetCode

C switch

last modified November 14, 2026

The switch statement dispatches execution to one of several labeled blocks, based on the value of an integer expression. It is the compact alternative to a long else if chain that compares one value with several constants. This tutorial covers the form of the statement, the rules for case labels and default, the fallthrough that makes grouping possible, and the mistakes the compiler catches.

The switch statement

The expression in the parentheses is evaluated once and must have an integer type: a character, an enum value or an integer of any size, but not a floating-point number. Each case label must then be an integer constant expression, a value the compiler can compute while compiling, so a variable cannot be used as a label. GCC also accepts a range such as case 1 ... 5: as an extension, but -pedantic-errors rejects it ("range expressions in switch statements are non-standard"), because the feature is not part of ISO C.

switch (value) {

    case 1:
        statements;
        break;

    case 2:
    case 3:
        statements;
        break;

    default:
        statements;
}

The statements after the matching label are executed, and execution continues until a break or the end of the switch. Without break, control falls through into the next label, which is sometimes useful and sometimes a bug. The default label is optional, may appear anywhere among the labels, and runs when no case matches.

A menu with switch

The first example asks for a single character and prints one of three messages. The space in the scanf format makes scanf skip leading whitespace before reading, so the program takes the first non-blank character of the input.

switch_menu.c
#include <stdio.h>

int main(void) {

    printf("Continue? y/n: ");

    char c;

    if (scanf(" %c", &c) != 1) {
        return 1;
    }

    switch (c) {

        case 'y':
            printf("program continues\n");
            break;

        case 'n':
            printf("program stops\n");
            break;

        default:
            printf("wrong option\n");
    }

    return 0;
}

Each branch ends with break, so exactly one message is printed, and the default branch handles every character other than 'y' and 'n'. Because the switch is the last statement of main, the missing break after default changes nothing; the label is last and the statement ends there anyway.

$ gcc -std=c17 -Wall -Wextra -o switch_menu switch_menu.c
$ printf 'y\n' | ./switch_menu
Continue? y/n: program continues

Grouping cases

Several case labels may share one block. The labels are written one after another without statements between them, and the block after the last label serves all of them. The next example groups the working days and the weekend days of a week.

switch_group.c
#include <stdio.h>

enum week { Mon, Tue, Wed, Thu, Fri, Sat, Sun };

int main(void) {

    enum week day = Wed;

    switch (day) {

        case Mon:
        case Tue:
        case Wed:
        case Thu:
        case Fri:
            printf("Weekday\n");
            break;

        case Sat:
        case Sun:
            printf("Weekend\n");
            break;

        default:
            printf("Unknown day\n");
    }

    return 0;
}

The enumeration constants are integer constant expressions, so they are valid labels, and day holds the value 2, which is Wed. The first label is Mon, but the labels simply fall through until the first statement, so the Weekday block runs. The default branch is unreachable for the seven values of the enumeration; it is kept because a value could still arrive from outside, for example through a cast from an integer read from input.

$ gcc -std=c17 -Wall -Wextra -o switch_group switch_group.c
$ ./switch_group
Weekday

Deliberate fallthrough

Fallthrough is not always an error. When the cases form a scale, each one can add its own contribution and then continue into the next, so the total accumulates. The next program computes a score from three levels.

switch_fallthrough.c
#include <stdio.h>

int main(void) {

    int level = 2;
    int score = 0;

    switch (level) {

        case 3:
            score += 100;
            /* fall through */
        case 2:
            score += 50;
            /* fall through */
        case 1:
            score += 10;
            break;

        default:
            score = 0;
    }

    printf("score = %d\n", score);

    return 0;
}

With level equal to 2, the matching label adds 50, falls through and adds 10, then leaves the switch at the break; the score is 60. The comment marks the jump for the reader and for the compiler: GCC enables -Wimplicit-fallthrough with -Wextra and accepts a comment that contains the words "fall through". Without such a comment it warns "this statement may fall through" for each such place.

$ gcc -std=c17 -Wall -Wextra -o switch_fallthrough switch_fallthrough.c
$ ./switch_fallthrough
score = 60

The switch expression

The value does not have to be a variable; any integer expression works, and the expression is evaluated only once. The labels may also be constant expressions, so case 1 + 1 is a valid way to write 2.

switch_expr.c
#include <stdio.h>

int main(void) {

    int n = 17;

    switch (n % 3) {

        case 0:
            printf("%d is divisible by 3\n", n);
            break;

        case 1:
            printf("%d leaves remainder 1\n", n);
            break;

        case 1 + 1:
            printf("%d leaves remainder 2\n", n);
            break;
    }

    return 0;
}

The remainder of 17 divided by 3 is 2, so the third label matches. The compiler computes 1 + 1 while translating the program, which is exactly what "integer constant expression" means. Since the remainder of a division by 3 is always 0, 1 or 2, the three labels cover every possible value and no default is needed.

$ gcc -std=c17 -Wall -Wextra -o switch_expr switch_expr.c
$ ./switch_expr
17 leaves remainder 2

Duplicate case labels

Two labels with the same value would make the choice ambiguous, so the compiler rejects them. The following program repeats the label case 1.

switch_duplicate.c
#include <stdio.h>

int main(void) {

    int n = 1;

    switch (n) {

        case 1:
            printf("one\n");
            break;

        case 1:
            printf("again\n");
            break;
    }

    return 0;
}

GCC reports the second label and points back to the first one, so the source of the clash is easy to find. The same error appears for labels that only look different, such as case 'a' and case 97 on an ASCII system, because both denote the same integer value.

$ gcc -std=c17 -Wall -Wextra -o switch_duplicate switch_duplicate.c
switch_duplicate.c: In function ‘main’:
switch_duplicate.c:13:9: error: duplicate case value
   13 |         case 1:
      |         ^~~~
switch_duplicate.c:9:9: note: previously used here
    9 |         case 1:
      |         ^~~~

switch or if else

A switch is the clearer choice when one integer value is compared with a fixed set of constants, especially when several constants share a branch. An else if chain is needed when the tests involve ranges, comparisons of different variables, floating-point values or strings, none of which a case label can express.

Keep a default branch in most switches, even when the current values seem to cover every case, so that an unexpected value is noticed rather than silently ignored. Give every branch a break unless the fallthrough is intentional, and mark the intentional ones with a comment. When a switch sits inside a loop, remember that its break leaves the switch and not the loop.

Source

cppreference: switch statement
cppreference: statements
GCC: warning options

This tutorial covered the switch statement: the integer expression it tests, the constant labels, the optional default, grouping several cases into one branch, the deliberate fallthrough marked with a comment, and the duplicate-label error. For the statement that leaves a switch, see the C break tutorial; the alternative chain of tests is described in C if & else, and loops in C for and C while.

Author

I am Jan Bodnar, a programmer and technical writer. I have been writing programming tutorials at ZetCode since 2007 and have published eight e-books. See about the author.

List all C tutorials.