トラック6・🔀制御構造

switch文とfallthrough

読む目安 約11分・ゴール:switch文で値による多分岐を書けるようになり、break忘れによるフォールスルーを理解する

アプリでこのトピックを学ぶ(無料・登録不要)

このトピックの要点

ラーメン屋の券売機を思い浮かべてください。「1番ならラーメン、2番ならチャーハン、3番なら餃子」。範囲ではなく、値がぴったり一致するかどうかで分かれます。こういうときはifを並べるよりswitch文のほうが読みやすくなります。

switch (式) {
    case 定数1:
        処理;
        break;
    case 定数2:
        処理;
        break;
    default:
        どれにも当てはまらなかったときの処理;
        break;
}

条件ではなく値で飛び先を選ぶのがポイントです。switch に置けるのは整数として扱える値だけ(int・char・列挙型など)で、文字列は使えません。また case x > 5: のような範囲指定も書けません。範囲で分けたいときは素直に else if を使います。

動く例です。

#include <stdio.h>

int main(void) {
    int menu = 2;

    switch (menu) {
        case 1:
            printf("ラーメン 800円\n");
            break;
        case 2:
            printf("チャーハン 750円\n");
            break;
        case 3:
            printf("餃子 400円\n");
            break;
        default:
            printf("その番号はありません\n");
            break;
    }
    return 0;
}

menu が 2 なので「チャーハン 750円」だけが表示されます。

さて、ここからが switch の本題です。case は部屋の入口ではなく、床に書かれたジャンプ先の目印にすぎません。だからbreakで止めないと、そのまま下の case へ歩いていってしまいます。これをフォールスルーと呼びます。

#include <stdio.h>

int main(void) {
    int menu = 1;

    switch (menu) {
        case 1:
            printf("ラーメン\n");    // break を忘れた
        case 2:
            printf("チャーハン\n");
            break;
    }
    return 0;
}

1番を選んだのに「ラーメン」と「チャーハン」の両方が出ます。case が5つ6つと並んだ状態で1つだけ break を落とすと、原因の特定にかなり手こずります。

師範case は部屋の入口ではない。床に書かれた目印じゃ。break という壁が無ければ、そのまま隣の部屋まで歩いていく

ただし、この性質はわざと使うこともあります。case を連続で並べると「まとめて同じ処理」が書けます。

#include <stdio.h>

int main(void) {
    int day = 7;   // 1=月 … 7=日

    switch (day) {
        case 6:
        case 7:
            printf("週末です\n");
            break;
        default:
            printf("平日です\n");
            break;
    }
    return 0;
}

case 6: には処理が何も書かれていないので、そのまま case 7: へ落ちて同じ処理を実行します。これは正しい、よくある書き方です。逆に言うと「処理を書いたのに break が無い」ものだけが疑わしい、と覚えておけば見分けられます。

最後の default は省略できますが、書いておくことを勧めます。想定外の値が来たときに気づけるからです。また default の中の break も文法上は不要ですが、あとから case を足したときの事故を防げます。

まとめます。switch は値がちょうど一致する多分岐。整数系の値にしか使えない。break を忘れると下へ流れ落ちる。case の連続だけは意図的なまとめ書き。

アプリでこのトピックを学ぶ(無料・登録不要)

確認問題

確認問題 1

次のプログラムを実行すると、何が表示されますか。

#include <stdio.h>

int main(void) {
    int menu = 3;

    switch (menu) {
        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行
  4. 何も表示されない
答えを見る

正解:A(餃子)

menu は 3 なので case 3: へジャンプして「餃子」を表示し、break で switch を抜けます。default は「どの case にも一致しなかったとき」だけ実行されるので、ここでは動きません。もし case 3: の break が無ければ、そのまま default へ流れ落ちて2行出ていました。

確認問題 2

level は 1 なので「初級」だけを表示したいのですが、実行すると「初級」と「中級」の2行が出てしまいます。原因となっている行(この直後に break が必要な行)はどこですか。

1#include <stdio.h>
2
3int main(void) {
4    int level = 1;
5
6    switch (level) {
7        case 1:
8            printf("初級\n");
9        case 2:
10            printf("中級\n");
11            break;
12        default:
13            printf("不明\n");
14            break;
15    }
16    return 0;
17}
答えを見る

バグのある行:8行目

8行目の printf("初級\n"); の直後に break; がありません。case は「区切り」ではなく「ジャンプ先の目印」なので、break で止めなければ下の case へそのまま流れ落ちます(フォールスルー)。8行目の次に break; を1行足せば「初級」だけが表示されます。

switch の case は床に書かれた目印のようなもので、部屋を仕切る壁ではありません。break を書かないと、そこから下の処理を case をまたいで実行し続けます。なお case 6: case 7: のように処理を書かずに case を連続させるのは意図的なまとめ書きで、これは正しい書き方です。「処理を書いたのに break が無い」ものだけが疑わしい、と覚えると見分けられます。

「制御構造」の目次

  1. 流れを変える——制御構造の全体像
  2. if文——もしも、の分かれ道
  3. else if / else の分かれ道設計
  4. 条件式の罠——= と == の悲劇
  5. 論理演算子と短絡評価
  6. switch文とfallthrough
  7. for文——回数が決まった繰り返し
  8. while文——条件が決める繰り返し
  9. do-while文と入力チェック
  10. breakとcontinueの使いどころ
  11. ループのネストと九九表
  12. 無限ループとの付き合い方

もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。

完全版の販売ページは準備中です。

ほかのトラック

📚 姉妹教材:手を動かして覚える Linux 教材 — Linuxとインフラの仕組みを地図で学ぶ

Web版