C言語のswitch文は、複数の条件分岐をすっきり書ける強力な構文です。
特にメニュー選択やエラーコード判定など、整数や文字の値によって処理を切り替えたい場面で活躍します。
本記事ではswitch文の基本から、break・default・複数case・実用サンプルまでを、図解とコード例を交えながら丁寧に解説します。
if文との違いや、書き忘れで起こりがちなバグもあわせて理解し、読みやすく安全なswitch文を書けるようになりましょう。
C言語のswitch文とは
switch文の基本構文と使いどころ

switch文は、1つの式の結果(整数や文字など)に応じて、複数の処理パターンから1つを選ぶための構文です。
典型的な書き方は次のようになります。
#include <stdio.h>
int main(void) {
int num = 2; // 判定したい値
// switch文の基本構文
switch (num) {
case 1: // num が 1 のとき
printf("num は 1 です。\n");
break; // ここで switch を抜ける
case 2: // num が 2 のとき
printf("num は 2 です。\n");
break;
case 3: // num が 3 のとき
printf("num は 3 です。\n");
break;
default: // どの case にも当てはまらないとき
printf("num は 1〜3 ではありません。\n");
break;
}
return 0;
}
num は 2 です。
switch文では、式の値と一致するcaseラベルの位置にジャンプし、そこから処理を実行します。
多くの場合は、それぞれのcaseの末尾にbreakを書き、そこでswitch文の処理を終えます。
switch文が活躍する典型的な場面としては、次のようなものがあります。
- メニュー番号(1〜5など)による処理分岐
- エラーコード(0、1、2、…)によるメッセージ表示
- キーボード入力された文字
('a', 'b', 'c')ごとの処理分岐
このように「決まった候補の中から1つを選ぶ」場合にswitch文は非常に読みやすいコードになります。
if文との違いと使い分けのポイント

if文とswitch文はどちらも条件分岐を行いますが、得意な分野が異なります。
if文の特徴
if文は、次のような複雑な条件に向いています。
- 範囲比較(cst-code>x < 10 && x >= 3など)
- 複数の条件の組み合わせ
- 浮動小数点(double, float)など、switchでは扱えない型
if (score >= 80) {
printf("合格\n");
} else if (score >= 60) {
printf("追試\n");
} else {
printf("不合格\n");
}
switch文の特徴
switch文は、同じ変数(または式)が特定の値に等しいかどうかを判定するのに向いています。
- 候補値がはっきり決まっている(1, 2, 3, …)
- 条件が「等しいかどうか」だけ
- 分岐パターンが多く、if文だと縦長になってしまう
switch (command) {
case 1:
// ...
break;
case 2:
// ...
break;
case 3:
// ...
break;
default:
// ...
break;
}
使い分けの目安
範囲や不等号を使うならif文、値の候補が列挙できるならswitch文を使うと覚えておくとよいです。
- 「80点以上なら合格」のように境界で分けたいとき → if文
- 「メニュー1〜4から1つ選ぶ」のように選択肢の番号で分けたいとき → switch文
caseラベルとbreakの基本
caseの書き方と値のルール

switch文の中には複数のcaseラベルを書き、どの値のときにどの処理を実行するかを指定します。
基本形はcase 定数値:です。
switch (式) {
case 0:
// 式 == 0 のときの処理
break;
case 1:
// 式 == 1 のときの処理
break;
case 2:
// 式 == 2 のときの処理
break;
default:
// どのcaseにも一致しないとき
break;
}
caseラベルの値には、次のようなルールがあります。
- 整数型に変換できる定数式のみが使用できます
- リテラル値
0, 1, 2 - 文字リテラル
'A', '0' - 定数マクロ
#defineで定義した値 - 列挙型
enumの列挙子
- リテラル値
- 同じswitch文の中で、同じ値のcaseを2回書くことはできません
たとえば、次のような書き方はエラーになります。
switch (x) {
case 1:
// ...
break;
case 1: // エラー: 同じ値の case が重複
// ...
break;
}
breakの役割と書き忘れによる落とし穴

breakは「ここでswitch文を抜ける」という命令です。
多くの場合、各caseの末尾にbreak;を書きます。
#include <stdio.h>
int main(void) {
int x = 1;
switch (x) {
case 1:
printf("case 1\n");
break; // ここで switch を終了
case 2:
printf("case 2\n");
break;
default:
printf("default\n");
break;
}
return 0;
}
case 1
ここでもしbreakを書き忘れると、次のcaseの処理まで続けて実行されてしまいます。
これをフォールスルー(fall-through)と呼びます。
#include <stdio.h>
int main(void) {
int x = 1;
switch (x) {
case 1:
printf("case 1\n");
// break を書き忘れた!
case 2:
printf("case 2\n");
break;
default:
printf("default\n");
break;
}
return 0;
}
case 1
case 2
このように、意図しないフォールスルーは典型的なバグの原因になります。
各caseの末尾には必ずbreakを書くことを習慣化すると安全です。
breakをあえて省略するケース

一方で、あえてbreakを書かずにフォールスルーを利用することもあります。
代表的なのは、複数のcaseを同じ処理にまとめたいときです。
#include <stdio.h>
int main(void) {
char c = 'A';
switch (c) {
case 'A':
case 'a': // 'A' と 'a' のどちらも同じ処理
printf("A または a が入力されました。\n");
break;
default:
printf("それ以外の文字が入力されました。\n");
break;
}
return 0;
}
A または a が入力されました。
このように、同じ処理を共有したい複数のcaseを、breakなしで並べることで、コードの重複を避けられます。
ただし、意図的なフォールスルーを使う場合でも、コメントで「フォールスルーする」ことを明示すると、他の人や未来の自分が読んだときに誤解しにくくなります。
defaultと複数caseの書き方
defaultの意味と配置場所のルール

defaultは、どのcaseにも一致しなかったときに実行される「その他」用のラベルです。
書き方は次のようになります。
switch (value) {
case 0:
// ...
break;
case 1:
// ...
break;
default: // 0でも1でもないとき
// ...
break;
}
defaultには次のようなルールがあります。
- 1つのswitch文の中に書けるdefaultは1つだけです
- 書く位置はどこでもよいですが、最後に書くのが一般的です
defaultを最後以外の場所に書いた例も、文法的には有効です。
switch (x) {
case 0:
// ...
break;
default: // ここで default
// ...
break;
case 1:
// ...
break;
}
ただし、このように書くと読み手を混乱させる可能性が高いので、実務ではほぼ必ず最後に書きます。
複数のcaseをまとめて処理する書き方

複数のcaseを同じ処理にしたい場合、caseラベルを連続して書き、最後のブロックにだけ処理を書くことで、シンプルにまとめられます。
#include <stdio.h>
int main(void) {
int month = 5;
switch (month) {
case 3:
case 4:
case 5:
printf("春です。\n");
break;
case 6:
case 7:
case 8:
printf("夏です。\n");
break;
case 9:
case 10:
case 11:
printf("秋です。\n");
break;
case 12:
case 1:
case 2:
printf("冬です。\n");
break;
default:
printf("月は 1〜12 を指定してください。\n");
break;
}
return 0;
}
春です。
ここでは、3,4,5 → 春 / 6,7,8 → 夏 …というように、季節ごとにまとめています。
同じ処理をコピペせずに書けるため、保守性も高くなります。
文字(char)や列挙型(enum)を使ったswitch文

switch文でよく使われるのはint型ですが、char型やenum(列挙型)も利用できます。
char型を使った例
#include <stdio.h>
int main(void) {
char op = '+';
switch (op) {
case '+':
printf("足し算をします。\n");
break;
case '-':
printf("引き算をします。\n");
break;
case '*':
printf("掛け算をします。\n");
break;
case '/':
printf("割り算をします。\n");
break;
default:
printf("不正な演算子です。\n");
break;
}
return 0;
}
足し算をします。
文字リテラル'+'や'A'は、内部的には整数値として扱われるため、switch文で問題なく使用できます。
enum(列挙型)を使った例
enumを使うと、意味のある名前で状態やモードを表現でき、コードの可読性が上がります。
#include <stdio.h>
// 動作モードを表す列挙型
typedef enum {
MODE_AUTO, // 0
MODE_MANUAL, // 1
MODE_TEST // 2
} Mode;
int main(void) {
Mode mode = MODE_MANUAL;
switch (mode) {
case MODE_AUTO:
printf("自動モードです。\n");
break;
case MODE_MANUAL:
printf("手動モードです。\n");
break;
case MODE_TEST:
printf("テストモードです。\n");
break;
default:
// 通常はここには来ない想定だが、安全のために書く
printf("不明なモードです。\n");
break;
}
return 0;
}
手動モードです。
このようにenum + switchの組み合わせは、状態遷移やモード分岐を表す際にとても便利です。
実用的なswitch文サンプル集
メニュー選択で使うswitch文の例

コンソールプログラムでよくあるのが、数字でメニューを選択させるパターンです。
switch文を使うと、各メニューの処理を見通しよく書けます。
#include <stdio.h>
int main(void) {
int choice;
// メニュー表示
printf("=== メニュー ===\n");
printf("1: 新規ゲーム開始\n");
printf("2: オプション設定\n");
printf("3: 終了\n");
printf("番号を選んでください: ");
scanf("%d", &choice); // ユーザーから番号を読み取る
// 入力された番号に応じて処理を分岐
switch (choice) {
case 1:
printf("新規ゲームを開始します。\n");
// ここにゲーム開始処理を書く
break;
case 2:
printf("オプション設定画面を開きます。\n");
// ここに設定処理を書く
break;
case 3:
printf("プログラムを終了します。\n");
// 終了処理
break;
default:
printf("不正な番号が入力されました。\n");
break;
}
return 0;
}
=== メニュー ===
1: 新規ゲーム開始
2: オプション設定
3: 終了
番号を選んでください: 2
オプション設定画面を開きます。
このように、メニュー番号と処理内容が1対1で対応しているケースでは、switch文が非常に読みやすくなります。
エラーコード分岐に使うswitch文の例

エラーコードが整数で定義されている場合にも、switch文は便利です。
エラーコードとメッセージを一覧で管理できます。
#include <stdio.h>
// 仮のエラーコード定義
#define ERR_OK 0
#define ERR_NOT_FOUND 1
#define ERR_ACCESS_DENY 2
#define ERR_TIMEOUT 3
void print_error_message(int err) {
switch (err) {
case ERR_OK:
printf("エラーは発生していません。\n");
break;
case ERR_NOT_FOUND:
printf("ファイルが見つかりません。\n");
break;
case ERR_ACCESS_DENY:
printf("アクセスが拒否されました。\n");
break;
case ERR_TIMEOUT:
printf("タイムアウトが発生しました。\n");
break;
default:
printf("不明なエラーコードです。(コード: %d)\n", err);
break;
}
}
int main(void) {
print_error_message(ERR_NOT_FOUND);
print_error_message(999); // 未定義のエラーコード
return 0;
}
ファイルが見つかりません。
不明なエラーコードです。(コード: 999)
定数マクロやenumでエラーコードを定義し、switchで分岐する形にしておくと、コードが整理され、他の人にも意図が伝わりやすくなります。
switch文を安全に書くためのベストプラクティス

最後に、switch文を安全かつ読みやすく書くためのポイントを整理します。
1. すべてのcaseの末尾にbreakを書く(意図的な例外を除く)
breakの書き忘れは典型的なバグです。
フォールスルーを使わないのであれば、すべてのcaseの末尾にbreakを付ける習慣を徹底しましょう。
switch (x) {
case 1:
// 処理
break; // 忘れない
case 2:
// 処理
break;
// ...
}
2. フォールスルーはコメントで明示する
フォールスルーを意図して使う場合は、コメントで明示することで、読み間違いを防げます。
switch (c) {
case 'A':
// 'A' は 'a' と同じ処理にする
/* fall through */
case 'a':
printf("A または a\n");
break;
}
意図的なフォールスルーだけが残るようにすると、コードレビューでも判断しやすくなります。
3. defaultはできる限り用意する
例外や想定外の値を受け取ったときの安全弁として、defaultを用意することが推奨されます。
- 不正な値を検知してエラーメッセージを出す
- ログを出力して原因調査に役立てる
default:
printf("不正な値です。(value = %d)\n", value);
break;
「ここには絶対に来ないはず」と思っていても、将来の仕様変更やバグで来てしまう可能性があるため、defaultで安全側に倒しておくのが無難です。
4. enumと組み合わせて使う
状態やモードを整数の「生値」で扱うより、enumで名前を付けてからswitch文で分岐したほうが、コードの意味が明確になります。
typedef enum {
STATE_INIT,
STATE_RUNNING,
STATE_STOPPED
} State;
void handle_state(State s) {
switch (s) {
case STATE_INIT:
// 初期化処理
break;
case STATE_RUNNING:
// 実行中処理
break;
case STATE_STOPPED:
// 停止中処理
break;
default:
// 想定外の状態
break;
}
}
このようにenumと組み合わせることで、状態の追加・削除があっても追いやすい構造になります。
5. 条件が複雑になりすぎる場合はif文や他の構造も検討する
switch文は単純な比較には強いですが、範囲比較や複合条件には向きません。
そのような場合は、if文に切り替えたり、関数ポインタや表駆動など別の設計を検討することも大切です。
まとめ
switch文は、「1つの値」によって処理を切り替える場面で非常に有効な構文です。
if文との違いを理解し、caseラベル・break・defaultの役割を正しく押さえることで、読みやすく安全なコードを書けるようになります。
特に「すべてのcaseにbreakを書く」「defaultを用意する」「意図的なフォールスルーにはコメント」という3点を意識しておくと、バグの少ないswitch文を実現できます。
メニュー選択やエラーコード分岐など、実用的な場面で積極的にswitch文を活用し、C言語の条件分岐を一段階レベルアップさせていきましょう。
