One Value, Many Constants
An else if chain that keeps comparing the same variable against constants is a pattern with a dedicated statement in C:
if (choice == 1) { /* ... */ }
else if (choice == 2) { /* ... */ }
else if (choice == 3) { /* ... */ }
else { /* ... */ }
switch says that more directly. It evaluates the expression once, then jumps straight to the matching label.
Change choice and run it again. The structure makes the set of legal values visible at a glance, which is the real reason to prefer it here.
Syntax and the Rules on Case Labels
switch (integerExpression) {
case CONSTANT_1:
statements
break;
case CONSTANT_2:
statements
break;
default:
statements
break;
}
Four constraints C enforces:
- The switch expression must have an integer type -
int,char,short,long, or anenum. Notfloat, notdouble, and not a string. - Every
caselabel must be a constant expression known at compile time.case n:wherenis a variable is an error;case 3 + 4:andcase MAX:(a#defineor enum constant) are fine. - No two cases may have the same value. Duplicates are a compile error, which is a small but genuine safety net.
- A case cannot express a range.
case 1 ... 5:is a GCC extension, not standard C; use aniffor ranges.
default is optional and may appear anywhere in the block, though putting it last is the near-universal convention. Without a default, an unmatched value simply skips the entire switch.
break: Why It Is Not Optional
The single most surprising thing about switch in C is that case labels are jump targets, not boxes. Once execution lands on a label it keeps going through every statement below it - across other case labels - until a break or the closing brace.
The first switch prints one, two, and three - it matched case 1 and then ran everything after it. The second prints only one. That behaviour is called fall-through, and forgetting a break is the classic C switch bug: the program is silently wrong rather than failing to compile.
Compile with gcc -Wall -Wextra -Wimplicit-fallthrough and the compiler points at every case that falls into the next one.
The break on the last case is technically redundant - the block ends there anyway. Write it anyway, so that adding a new case below it later does not quietly create a fall-through.
Deliberate Fall-Through
Fall-through is a feature when it is intentional. Stacking labels with no statements between them is the ordinary way to say "these values do the same thing":
Three labels share one body, with no duplicated code and no long || condition. Compilers do not warn about this shape, because there are no statements to fall through.
Fall-through with statements in between - where case 1 runs and then deliberately continues into case 2 - is rarer and deserves an explicit comment, since a reader has to be told the missing break was a decision:
switch (level) {
case 3:
printf("verbose\n");
/* fall through */
case 2:
printf("info\n");
/* fall through */
case 1:
printf("errors\n");
break;
}
/* fall through */ is the comment GCC's warning recognises, so it also silences the diagnostic.
Switching on Characters
Because char is an integer type, character classification is a natural fit:
Note case 'a': uses single quotes - a character constant, which is just the integer value of that character. case "a": would be a string and will not compile.
Switching on Enums
The best pairing in C is switch with an enum. The case labels become readable names, and compilers can warn when the switch does not handle every enumerator:
Two things worth copying here. Each case returns, so no break is needed - a return leaves the function entirely, which also ends the switch. And there is no default: with -Wswitch (included in -Wall), leaving default off makes the compiler warn the day someone adds a fifth state and forgets this function. A default would have hidden that.
Declaring Variables Inside a switch
A switch body is one block, so a declaration in one case is visible - though not necessarily initialised - in the ones after it. Jumping over an initialisation is an error in C:
switch (n) {
case 1:
int x = 10; // error in C: a label cannot precede a declaration this way
printf("%d\n", x);
break;
case 2:
printf("%d\n", x); // x exists here, but was never initialised
break;
}
Wrap the case in its own braces when it needs local variables:
switch (n) {
case 1: {
int x = 10;
printf("%d\n", x);
break;
}
case 2:
printf("two\n");
break;
}
switch or if-else?
Reach for switch when all of this is true: you are testing one expression, it has an integer type, and you are comparing it against fixed constants. Menu handling, enum state machines, character classification, and command dispatch are the canonical cases. The payoff is readability, duplicate-value checking, and a compiler that can warn about unhandled enumerators.
Reach for if-else when the tests involve ranges (score >= 90), floating-point values, strings (you need strcmp), several different variables, or conditions combined with && and ||. None of those can be expressed as a case label.
Performance is rarely the deciding factor. Compilers turn a dense switch into a jump table and a sparse one into comparisons, so on a handful of cases the two forms are indistinguishable. Choose the one that states the intent.
Frequently Asked Questions
How does a switch statement work in C?
switch (expr) evaluates an integer expression once, jumps to the case label whose constant matches, and runs from there until it hits a break or the end of the switch. If nothing matches, it jumps to default when one is present, and otherwise skips the whole block.
Why do I need break in a C switch?
Because case labels are jump targets, not separate blocks. Without a break, execution continues straight into the next case's statements - this is called fall-through. A missing break is the most common switch bug in C, and gcc -Wimplicit-fallthrough will flag it.
Can you switch on a string in C?
No. A C switch requires an integer expression, so int, char, and enum values work, but strings, floats, and ranges do not. To branch on a string, use strcmp in an if-else chain, or map the string to an enum first and switch on that.
When should I use switch instead of if-else in C?
Use switch when you are comparing one integer or character against a list of fixed constants - menu commands, enum states, character classification. Use an if-else chain when the tests involve ranges, multiple variables, or anything other than equality against a compile-time constant.