The Switch Statement (Case): A Visual, Hands-On Guide
Learn the switch statement visually: how it jumps straight to a case, break and fall-through, stacked cases, enums and the compiler warnings that protect you, state machines, what C++ won't let you switch on, a real benchmark and exercises with answers.

On this page
Menus, game controls, days of the week, traffic lights: lots of decisions boil down to "look at this one value, and do something different for each possibility". You could write that as a long chain of if / else if. The switch statement is a tidier tool built exactly for this job.
In this guide you'll see how a switch picks its case, the famous break gotcha (and when falling through is actually handy), how enums and compiler warnings keep you safe, how to build a little state machine, and what C++ won't let you switch on. There's a real benchmark too, and exercises with answers at the end.
One value, many possible paths
An if/else chain asks its questions one at a time, top to bottom. A switch looks at a value once and goes straight to the matching case:

Here's a switch that names the day of the week:
1#include <iostream>
2
3int main() {
4 int day;
5 std::cout << "Day of the week (1-7): ";
6 std::cin >> day;
7
8 switch (day) {
9 case 1:
10 std::cout << "Monday\n";
11 break;
12 case 2:
13 std::cout << "Tuesday\n";
14 break;
15 case 3:
16 std::cout << "Wednesday\n";
17 break;
18 case 4:
19 std::cout << "Thursday\n";
20 break;
21 case 5:
22 std::cout << "Friday\n";
23 break;
24 case 6:
25 std::cout << "Saturday\n";
26 break;
27 case 7:
28 std::cout << "Sunday\n";
29 break;
30 default:
31 std::cout << "There is no day " << day << "!\n";
32 }
33}Three sample runs:
Day of the week (1-7): 3
WednesdayDay of the week (1-7): 9
There is no day 9!Day of the week (1-7): 0
There is no day 0!The parts of a switch

switch (value): the value to look at. In C++ it must be a whole-number type:int,char, anenum, and so on.case 3:: a label marking where to start running when the value is 3. Labels must be constants.break;: leave the switch and continue after its closing brace.default:: where to go when no case matches, like the finalelseof an if chain. It's optional, but usually a good idea.
The big gotcha: forgetting break
A case label is just a place to jump to, not a wall. Once execution lands on a case, it keeps running downward, right through the other labels, until it reaches a break or the end of the switch. This is called fall-through:

1#include <iostream>
2
3int main() {
4 int level = 2;
5
6 switch (level) {
7 case 1:
8 std::cout << "Unlocked: sword\n";
9 case 2:
10 std::cout << "Unlocked: shield\n";
11 case 3:
12 std::cout << "Unlocked: dragon\n";
13 default:
14 std::cout << "Unlocked: everything else\n";
15 }
16}Unlocked: shield
Unlocked: dragon
Unlocked: everything elseLevel 2 unlocked the dragon. Oops! Luckily, GCC warns about this when you compile with -Wextra:
1fallthrough.cpp: In function 'int main()':
2fallthrough.cpp:8:26: warning: this statement may fall through [-Wimplicit-fallthrough=]
3 8 | std::cout << "Unlocked: sword\n";
4 | ^~~~~~~~~~~~~~~~~~~
5fallthrough.cpp:9:9: note: here
6 9 | case 2:
7 | ^~~~
8fallthrough.cpp:10:26: warning: this statement may fall through [-Wimplicit-fallthrough=]
9 10 | std::cout << "Unlocked: shield\n";
10 | ^~~~~~~~~~~~~~~~~~~~
11fallthrough.cpp:11:9: note: here
12 11 | case 3:
13 | ^~~~
14fallthrough.cpp:12:26: warning: this statement may fall through [-Wimplicit-fallthrough=]
15 12 | std::cout << "Unlocked: dragon\n";
16 | ^~~~~~~~~~~~~~~~~~~~
17fallthrough.cpp:13:9: note: here
18 13 | default:
19 | ^~~~~~~When falling through is what you want
Fall-through has two good uses.
1. Several values, one action. Stack case labels with nothing between them, and they all share the same code. Here C and D both get "Okay…":
1#include <iostream>
2
3int main() {
4 char grades[] = {'A', 'B', 'C', 'D', 'F', 'Z'};
5
6 for (char grade : grades) {
7 std::cout << grade << ": ";
8 switch (grade) {
9 case 'A':
10 std::cout << "Excellent!\n";
11 break;
12 case 'B':
13 std::cout << "Great!\n";
14 break;
15 case 'C':
16 case 'D':
17 std::cout << "Okay...\n";
18 break;
19 case 'F':
20 std::cout << "Time to study together.\n";
21 break;
22 default:
23 std::cout << "Invalid grade.\n";
24 }
25 }
26}1A: Excellent!
2B: Great!
3C: Okay...
4D: Okay...
5F: Time to study together.
6Z: Invalid grade.A char works in a switch because a character is really a small number: 'A' is stored as 65.
2. Doing this, and then everything after it. When falling through on purpose, mark it with [[fallthrough]]; (C++17). It tells both human readers and the compiler "yes, I meant that", and the warning goes away:
1#include <iostream>
2
3int main() {
4 int secondsLeft = 3;
5
6 std::cout << "Launch in: ";
7 switch (secondsLeft) {
8 case 3:
9 std::cout << "3... ";
10 [[fallthrough]]; // on purpose: keep going into case 2
11 case 2:
12 std::cout << "2... ";
13 [[fallthrough]];
14 case 1:
15 std::cout << "1... ";
16 [[fallthrough]];
17 case 0:
18 std::cout << "Liftoff!\n";
19 break;
20 }
21}Launch in: 3... 2... 1... Liftoff!Switches and enums: a perfect match
Bare numbers like case 2: don't say much. An enum gives names to a fixed set of values, and enum class (C++11) keeps those names neatly grouped. Here's a game character moving around a grid:
1#include <iostream>
2
3enum class Direction { Up, Down, Left, Right };
4
5int main() {
6 int row = 5;
7 int column = 5;
8 Direction moves[] = {Direction::Up, Direction::Up, Direction::Right, Direction::Down};
9
10 for (Direction move : moves) {
11 switch (move) {
12 case Direction::Up:
13 row--;
14 break;
15 case Direction::Down:
16 row++;
17 break;
18 case Direction::Left:
19 column--;
20 break;
21 case Direction::Right:
22 column++;
23 break;
24 }
25 std::cout << "Now at row " << row << ", column " << column << "\n";
26 }
27}1Now at row 4, column 5
2Now at row 3, column 5
3Now at row 3, column 6
4Now at row 4, column 6case Direction::Up: reads like plain English, and you can't accidentally write case 7: for a direction that doesn't exist.
The compiler checks you covered every case
There's a bonus. When you switch on an enum without a default, the compiler knows every possible value and warns you if you forget one. Here the Right case is missing:
1enum class Direction { Up, Down, Left, Right };
2
3int columnChange(Direction move) {
4 switch (move) {
5 case Direction::Up:
6 return 0;
7 case Direction::Down:
8 return 0;
9 case Direction::Left:
10 return -1;
11 }
12 return 0;
13}GCC with -Wall:
1missingcase.cpp: In function 'int columnChange(Direction)':
2missingcase.cpp:4:12: warning: enumeration value 'Right' not handled in switch [-Wswitch]
3 4 | switch (move) {
4 | ^A switch inside a loop: state machines
Put a switch inside a loop, switch on "what state am I in?", and you've built a state machine: one of the most useful patterns in programming. Traffic lights, vending machines, game characters (idle, walking, jumping) and network connections all work this way.

1#include <iostream>
2
3enum class Light { Green, Yellow, Red };
4
5int main() {
6 Light light = Light::Green;
7
8 for (int tick = 1; tick <= 6; tick++) {
9 switch (light) {
10 case Light::Green:
11 std::cout << "Tick " << tick << ": GREEN -> go\n";
12 light = Light::Yellow;
13 break;
14 case Light::Yellow:
15 std::cout << "Tick " << tick << ": YELLOW -> slow down\n";
16 light = Light::Red;
17 break;
18 case Light::Red:
19 std::cout << "Tick " << tick << ": RED -> stop\n";
20 light = Light::Green;
21 break;
22 }
23 }
24}1Tick 1: GREEN -> go
2Tick 2: YELLOW -> slow down
3Tick 3: RED -> stop
4Tick 4: GREEN -> go
5Tick 5: YELLOW -> slow down
6Tick 6: RED -> stopWhat C++ won't let you switch on

No strings
This is the most common surprise for people coming from other languages:
1#include <iostream>
2#include <string>
3
4int main() {
5 std::string greeting = "Hello";
6 switch (greeting) {
7 case "Hello":
8 std::cout << "Hello, dolly!\n";
9 break;
10 }
11}1strings.cpp: In function 'int main()':
2strings.cpp:6:13: error: switch quantity not an integer
3 6 | switch (greeting) {
4 | ^~~~~~~~Two good alternatives: an if/else chain (if (greeting == "Hello") …), or, when you have many pairs, a lookup table like std::map:
1#include <iostream>
2#include <map>
3#include <string>
4
5int main() {
6 std::map<std::string, std::string> replies = {
7 {"Morning", "Good morning to you, too!"},
8 {"Hello", "Hello, dolly!"},
9 {"Night", "Good night!"},
10 };
11
12 for (std::string greeting : {"Hello", "Night", "Yo"}) {
13 auto found = replies.find(greeting);
14 if (found != replies.end()) {
15 std::cout << greeting << " -> " << found->second << "\n";
16 } else {
17 std::cout << greeting << " -> What's up?\n";
18 }
19 }
20}Hello -> Hello, dolly!
Night -> Good night!
Yo -> What's up?No duplicate cases
1int price(int size) {
2 switch (size) {
3 case 1: return 3;
4 case 2: return 4;
5 case 2: return 5;
6 }
7 return 0;
8}1duplicate.cpp: In function 'int price(int)':
2duplicate.cpp:5:9: error: duplicate case value
3 5 | case 2: return 5;
4 | ^~~~
5duplicate.cpp:4:9: note: previously used here
6 4 | case 2: return 4;
7 | ^~~~Declaring a variable inside a case needs braces
This one puzzles almost everybody the first time:
1#include <iostream>
2
3int main() {
4 int choice = 2;
5 switch (choice) {
6 case 1:
7 int bonus = 10;
8 std::cout << bonus << "\n";
9 break;
10 case 2:
11 std::cout << "two\n";
12 break;
13 }
14}1crosses.cpp: In function 'int main()':
2crosses.cpp:10:14: error: jump to case label
3 10 | case 2:
4 | ^
5crosses.cpp:7:17: note: crosses initialization of 'int bonus'
6 7 | int bonus = 10;
7 | ^~~~~The whole switch is one block, so bonus would still exist in case 2, but jumping there skips its initialization. The fix is to give the case its own block with braces: case 1: { int bonus = 10; … break; }. You'll see this in the days-in-month answer below.
Is a switch faster than if/else?
You'll often hear that a switch is faster because of its jump table. We tested it: the same 16-way decision on 50 million random values, written both ways, with each case calling a different function:

Looking at the machine code GCC produced, the optimized build used a jump table for both versions: the compiler recognized that the if/else chain was really a switch in disguise. Without optimization, only the switch got one.
Which one should you use?

The same idea in other languages
Many languages can switch on strings. JavaScript works just like C++, plus strings:
1const greeting = "Hello";
2switch (greeting) {
3 case "Morning":
4 console.log("Good morning to you, too!");
5 break;
6 case "Hello":
7 console.log("Hello, dolly!");
8 break;
9 default:
10 console.log("What's up?");
11}Python (3.10 and later) has match, which never falls through and uses | for "either of these":
1greeting = "Hello"
2match greeting:
3 case "Morning":
4 print("Good morning to you, too!")
5 case "Hello" | "Hi":
6 print("Hello, dolly!")
7 case _:
8 print("What's up?")Both print Hello, dolly!.
| Language | Switch on strings? | Falls through without break? |
|---|---|---|
| C, C++ | No | Yes |
| Java, JavaScript, PHP | Yes | Yes |
| C# | Yes | No: it's a compile error to fall out of a non-empty case |
Python (match) | Yes | No |
| Go | Yes | No (unless you write fallthrough) |
Practice time
Try these before peeking at the answers. Copy each program into a file, compile with g++ -std=c++20 -Wall -Wextra program.cpp, and run it.
Exercise 1: Predict the output (warm-up). What does this print?
1int number = 2;
2switch (number) {
3 case 1:
4 std::cout << "one ";
5 case 2:
6 std::cout << "two ";
7 case 3:
8 std::cout << "three ";
9 break;
10 case 4:
11 std::cout << "four ";
12}Exercise 2: Pocket calculator. Given two numbers and an operator character ('+', '-', '*' or '/'), print the result. Anything else should print unknown operation.
Exercise 3: Count the vowels. Using a switch with stacked cases, count the vowels in "switch statements are fun".
Exercise 4: Days in a month. Write int daysInMonth(int month, int year). April, June, September and November have 30 days; February has 28, or 29 in a leap year; the rest have 31.
Exercise 5: Rewrite it. Turn this into a switch. Which version do you find easier to read?
1if (key == 'w') moveUp();
2else if (key == 's') moveDown();
3else if (key == 'a') moveLeft();
4else if (key == 'd') moveRight();
5else beep();Exercise 6: A coin-operated turnstile (challenge). A turnstile starts Locked. A coin unlocks it; a push lets one person through and locks it again. Pushing a locked turnstile does nothing, and a coin in an unlocked one is just a tip. Feed it the events push, coin, push, push, coin, coin and print what happens.

Quick quiz
- What happens if you leave out
breakat the end of a case? - Can you
switchon astd::stringin C++? What can you do instead? - Why does
switch (grade)work whengradeis achar? - When might you leave out
defaulton purpose? - What does
[[fallthrough]];do?
Answers
Exercise 1: two three. It jumps to case 2, prints "two ", falls through into case 3, prints "three ", then hits break.
two three Exercise 2:
1#include <iostream>
2
3int main() {
4 double first = 12;
5 double second = 4;
6 char operations[] = {'+', '-', '*', '/', '%'};
7
8 for (char operation : operations) {
9 std::cout << first << " " << operation << " " << second << " = ";
10 switch (operation) {
11 case '+':
12 std::cout << first + second << "\n";
13 break;
14 case '-':
15 std::cout << first - second << "\n";
16 break;
17 case '*':
18 std::cout << first * second << "\n";
19 break;
20 case '/':
21 std::cout << first / second << "\n";
22 break;
23 default:
24 std::cout << "unknown operation\n";
25 }
26 }
27}112 + 4 = 16
212 - 4 = 8
312 * 4 = 48
412 / 4 = 3
512 % 4 = unknown operationExercise 3: Five stacked labels share one vowels++:
1#include <iostream>
2#include <string>
3
4int main() {
5 std::string sentence = "switch statements are fun";
6 int vowels = 0;
7 for (char letter : sentence) {
8 switch (letter) {
9 case 'a':
10 case 'e':
11 case 'i':
12 case 'o':
13 case 'u':
14 vowels++;
15 break;
16 }
17 }
18 std::cout << "Vowels: " << vowels << "\n";
19}Vowels: 7Exercise 4: Stacked cases for the 30-day months, braces around February's block because it declares a variable, and default for the 31-day months:
1#include <iostream>
2
3int daysInMonth(int month, int year) {
4 switch (month) {
5 case 4:
6 case 6:
7 case 9:
8 case 11:
9 return 30;
10 case 2: {
11 bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
12 return isLeapYear ? 29 : 28;
13 }
14 default:
15 return 31;
16 }
17}
18
19int main() {
20 std::cout << "January 2025: " << daysInMonth(1, 2025) << "\n";
21 std::cout << "April 2025: " << daysInMonth(4, 2025) << "\n";
22 std::cout << "February 2025: " << daysInMonth(2, 2025) << "\n";
23 std::cout << "February 2024: " << daysInMonth(2, 2024) << "\n";
24}1January 2025: 31
2April 2025: 30
3February 2025: 28
4February 2024: 29return leaves the whole function, so these cases don't need break.
Exercise 5:
1switch (key) {
2 case 'w': moveUp(); break;
3 case 's': moveDown(); break;
4 case 'a': moveLeft(); break;
5 case 'd': moveRight(); break;
6 default: beep();
7}Most people find the switch easier to scan: every option lines up, and it's obvious that they all test the same key.
Exercise 6: A switch on the state, with an if inside each case for the event:
1#include <iostream>
2#include <string>
3
4enum class State { Locked, Unlocked };
5
6int main() {
7 State state = State::Locked;
8 std::string events[] = {"push", "coin", "push", "push", "coin", "coin"};
9
10 for (const std::string& event : events) {
11 switch (state) {
12 case State::Locked:
13 if (event == "coin") {
14 state = State::Unlocked;
15 std::cout << event << ": unlocked, come on through\n";
16 } else {
17 std::cout << event << ": still locked, insert a coin\n";
18 }
19 break;
20 case State::Unlocked:
21 if (event == "push") {
22 state = State::Locked;
23 std::cout << event << ": you passed, locked again\n";
24 } else {
25 std::cout << event << ": already unlocked, thanks for the tip\n";
26 }
27 break;
28 }
29 }
30}1push: still locked, insert a coin
2coin: unlocked, come on through
3push: you passed, locked again
4push: still locked, insert a coin
5coin: unlocked, come on through
6coin: already unlocked, thanks for the tipQuiz: (1) Execution falls through into the next case's code, and keeps going until a break or the end of the switch. (2) No; use an if/else chain or a lookup table such as std::map. (3) A char is a small whole number underneath ('A' is 65). (4) When switching on an enum, so the compiler warns you if a value isn't handled. (5) It marks a fall-through as intentional, for readers and for the compiler, which then doesn't warn.
Cheat sheet
| I want to… | Write |
|---|---|
| Pick an action by value | switch (value) { case 1: …; break; case 2: …; break; } |
| Handle "anything else" | default: … |
| Give several values the same action | case 'C': case 'D': …; break; |
| Fall through on purpose | [[fallthrough]]; before the next label |
| Use readable names | enum class Direction { Up, Down }; then case Direction::Up: |
| Get warned about missing enum cases | switch on the enum with no default, compile with -Wall |
| Declare a variable inside a case | wrap it in braces: case 1: { int bonus = 10; … break; } |
| Choose by string | if (text == "Hello") … else if … or a std::map |
| Build a state machine | a switch (state) inside a loop that updates state |
Wrapping up
The switch statement is a clean way to say "look at this value and pick the matching path":
- A switch jumps to the matching
case, anddefaultcatches everything else. breakmatters: without it, execution falls through into the cases below.-Wextrawarns you, and[[fallthrough]]marks the times you mean it.- Stacked labels give several values the same action.
- Enums and switches go together: readable names, plus a warning when a value isn't handled.
- A switch in a loop makes a state machine, the heart of games, devices and protocols.
- C++ switches only work on whole numbers,
chars and enums. For strings, use if/else or astd::map. - Speed is a tie: with optimization on, GCC built the same jump table for an if/else chain. Choose the one that reads best.
Keep going with The If Statement, The For Loop and The While and Do-While Loops.
Learning the C++ programming language? How about doing it with One Hour a Day.
Read next

What Is the Swift Programming Language? A Simple Guide to the Language Behind iPhone Apps
A friendly, jargon-free guide to Swift, the programming language Apple created for iPhone, iPad and Mac apps. Learn why it replaced Objective-C, how optionals prevent crashes, how an app is made, and how fast Swift really is.

What Is the Rust Programming Language? A Simple Guide to the Fast Language That Won't Let You Crash
A friendly, jargon-free guide to Rust, the programming language that is as fast as C but stops whole families of memory bugs before a program ever runs. Learn about ownership, why tech giants are adopting it, and where it is used.

What Is the Go Programming Language? A Simple Guide to the Language of the Cloud
A friendly, jargon-free guide to Go, the simple and fast programming language Google created for the cloud. Learn what goroutines are, why Go programs are a single file, and how Go came to power Docker, Kubernetes and much of the internet.
Comments
Be kind and specific. Comments with links from new accounts appear after a moderator reviews them.