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.
#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.
#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.
#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.
#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.
#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
List all C tutorials.