カテゴリー

C言語

【C言語&switch文】C言語初心者がswitch文を学ぶ

2021年5月23日

こんな人にオススメ

C言語のswitch文ってなんなん?ifと何が違うん?

ということで、個人的な疑問のswitch文について自分で調べてコードを書いてみる。参考にしたのは以前と同様の猫Cこと「猫でもわかるC言語プログラミング」。

以前のVScodeでC言語を初めてみるという記事については以下参照。

スポンサーリンク
スポンサーリンク

運営者のメガネと申します。TwitterInstagramも運営中。

自己紹介はこちらから、お問い合わせはこちらからお願いいたします。

運営者メガネ

switch

そもそもswitch文は条件によって実行する処理が異なる場合に使用する文。ifでよくない?と言う声が聞こえるが、それについては後で書く。

switch文の基本構造

switch文の基本構造は以下の感じ。

switch (expression)
{
case /* constant-expression */:
    /* code */
    break;
case /* constant-expression */:
    /* code */
    break;

default:
    break;
}

expressionなどは全てVisual Studio Code(VScode)でswiと打ってエンターを押すだけで入力補完してくれたもの。VScodeのC言語の拡張機能が補完してくれているはず。

それぞれの部分に書く内容は以下。

  • expression: 制御文(条件文、式とも)
  • constant-expression: 事例式(定数、値、数値とも)
  • code: 文(処理とも)

expressionに書かれた内容が該当するcaseconstant-expressionが行われるということ。breakは処理の中断(終了)を表し、defaultは全てのcaseに当てはまらなかった場合の処理をかく。defaultの下には何もないがbreakの前に処理を書くことも可能。

switch文の一例

#include <stdio.h>

int main() {
    int n;

    for (n = 0; n <= 6; n++) {
        printf("入力値: %d\\t", n);

        switch (n) {
            case 1:
                printf("あなたは一番小さい数字を入力しましたね\\n");
                break;
            case 2:
                printf("今日は良いことがあるでしょう\\n");
                break;
            case 3:
                printf("中庸の徳です\\n");
                break;
            case 4:
                printf("4は幸せの4\\n");
                break;
            case 5:
                printf("あなたは5を選びました\\n");
                break;

            default:
                printf("1から5までの整数を入力してください\\n");
                break;
        }
    }
    printf("これでおしまいです\\n");
    return 0;
}

一例として猫Cに載っている例文を改造したものを示す。猫Cでは好きな値を入力し、その入力値に応じてprintfするものだった。

しかし、執筆者は普段VScodeの拡張機能「Code Runner」を使用し、さらに設定でターミナルでの出力はオフにしている。すなわち、入力を求めるコードは使用できない(ターミナルでの出力をオンにすればいいがターミナルは別の用途として使いたいのでオフにしている)。

したがって、このコードではforループで数値を回しながら値の確認を行なっている。なお、\\tはタブ記号で余白を入れたいから使用。

Code Runnerを含むVScodeの拡張機能については以下参照。

【VScode&拡張機能】python・C・LaTeX...ユーザーのVisual Studio Code拡張機能

続きを見る

実際の出力は以下。

/*
入力値: 0	1から5までの整数を入力してください
入力値: 1	あなたは一番小さい数字を入力しましたね
入力値: 2	今日は良いことがあるでしょう
入力値: 3	中庸の徳です
入力値: 4	4は幸せの4
入力値: 5	あなたは5を選びました
入力値: 6	1から5までの整数を入力してください
これでおしまいです
 */

1から5の入力にはそれらに対応したprintfが、1から5以外の数値には同じprintfができていることが確認できる。

if文との違い

switch文の基本構造はわかった。では、if文とは何が異なるのか。

結論、同じ。

ただ、場合分けをする条件が多数存在する場合ではif文だと文章が面倒だったり複雑になってしまう。それを解消するために用意されているのがswitch文のようだ。

if文でも同じ出力をしてみる

#include <stdio.h>

int main() {
    int n;

    for (n = 0; n <= 6; n++) {
        printf("入力値: %d\\t", n);

        if (n == 1) {
            printf("あなたは一番小さい数字を入力しましたね\\n");
        } else if (n == 2) {
            printf("今日は良いことがあるでしょう\\n");
        } else if (n == 3) {
            printf("中庸の徳です\\n");
        } else if (n == 4) {
            printf("4は幸せの4\\n");
        } else if (n == 5) {
            printf("あなたは5を選びました\\n");
        } else {
            printf("1から5までの整数を入力してください\\n");
        }
    }
    printf("これでおしまいです\\n");
    return 0;
}
/*
入入力値: 0	1から5までの整数を入力してください
入力値: 1	あなたは一番小さい数字を入力しましたね
入力値: 2	今日は良いことがあるでしょう
入力値: 3	中庸の徳です
入力値: 4	4は幸せの4
入力値: 5	あなたは5を選びました
入力値: 6	1から5までの整数を入力してください
これでおしまいです
 */

if文を使用した場合は上のコードとなる。コードの行数としては少なくなっているが、else ifの部分がごちゃついている印象(もちろん改行すれば印象は変わるが、今回は初期フォーマットしてくれたままにする)。

また、複数箇所選択と拡張機能「vscode-input-sequence」の使用で簡単に入力できるが、else if (n == 2) {の数値の部分の入力が煩わしい。複数選択からの連番作成は例えば以下のようにできる。

  1. ) {を選択
  2. cmd + dで複数選択
  3. 左カーソルでn == の後まで持っていく
  4. 数値が入っていたら消す
  5. vscode-input-sequenceで連番作成

あまり大差はないが、やはりコードの見渡しが悪いと煩わしいと感じてしまう。

breakをつけないとどうなる?

caseの各処理で毎回breakが入っているが、もしこれを削除した場合はどうなるのか。ここではコードの一部からbreakを削除した場合を見てみる。

#include <stdio.h>

int main() {
    int n;

    for (n = 0; n <= 6; n++) {
        printf("入力値: %d\\t", n);

        switch (n) {
            case 1:
                printf("あなたは一番小さい数字を入力しましたね\\n");
            case 2:
                printf("今日は良いことがあるでしょう\\n");
                break;
            case 3:
                printf("中庸の徳です\\n");
                break;
            case 4:
                printf("4は幸せの4\\n");
                break;
            case 5:
                printf("あなたは5を選びました\\n");

            default:
                printf("1から5までの整数を入力してください\\n");
        }
    }
    printf("これでおしまいです\\n");
    return 0;
}

上記のコードではcase 1case 5の後、そしてdefaultの後のbreakを消してみた。この場合の出力は以下の通り。

/*
入力値: 0	1から5までの整数を入力してください
入力値: 1	あなたは一番小さい数字を入力しましたね
今日は良いことがあるでしょう
入力値: 2	今日は良いことがあるでしょう
入力値: 3	中庸の徳です
入力値: 4	4は幸せの4
入力値: 5	あなたは5を選びました
1から5までの整数を入力してください
入力値: 6	1から5までの整数を入力してください
これでおしまいです
 */

case 1の後にbreakがないのでそのままcase 2が出力されていることがわかる。同様にcase 5の後にもbreakがないのでその後のdefaultが出力されている。

ただ、defaultの後にbreakがなくてもswitch内にはdefault後の出力がないので、ここはそのまま処理が進むようだ。

caseの時に「もしくは」としたい時はどうする?

これまではcaseにある一つの条件のみを使用して処理した。では、「もしくは」の時はどうすればよいのか。例えば「1もしくは2の時」のような感じ。

||で「もしくは」とする

#include <stdio.h>

int main() {
    int n;

    for (n = 0; n <= 7; n++) {
        printf("入力値: %d\\t", n);

        switch (n) {
            case 1:
                printf("あなたは一番小さい数字を入力しましたね\\n");
                break;
            case 2:
                printf("今日は良いことがあるでしょう\\n");
                break;
            case 3:
                printf("中庸の徳です\\n");
                break;
            case 4:
                printf("4は幸せの4\\n");
                break;
            case 5 || 6:
                printf("あなたは5もしくは6を選びました\\n");
                break;

            default:
                printf("1から6までの整数を入力してください\\n");
                break;
        }
    }
    printf("これでおしまいです\\n");
    return 0;
}

まずは和結合演算子(条件OR演算子)||を使用した場合を考える。この場合はwarningとerrorが出て実行できない。

/*
c_switch_pipe.c:22:20: warning: use of logical '||' with constant operand [-Wconstant-logical-operand]
            case 5 || 6:
                   ^  ~
c_switch_pipe.c:22:20: note: use '|' for a bitwise operation
            case 5 || 6:
                   ^~
                   |
c_switch_pipe.c:22:18: error: duplicate case value '1'
            case 5 || 6:
                 ^
c_switch_pipe.c:10:18: note: previous case defined here
            case 1:
                 ^
1 warning and 1 error generated.
*/

||を使用する場合は例えばif (a == 2 || a == 3)のように使用しなければいけない。caseでは使用できない。

caseを複数個にする

#include <stdio.h>

int main() {
    int n;

    for (n = 0; n <= 7; n++) {
        printf("入力値: %d\\t", n);

        switch (n) {
            case 1:
                printf("あなたは一番小さい数字を入力しましたね\\n");
                break;
            case 2:
                printf("今日は良いことがあるでしょう\\n");
                break;
            case 3:
                printf("中庸の徳です\\n");
                break;
            case 4:
                printf("4は幸せの4\\n");
                break;
            case 5:
            case 6:
                printf("あなたは5もしくは6を選びました\\n");
                break;

            default:
                printf("1から6までの整数を入力してください\\n");
                break;
        }
    }
    printf("これでおしまいです\\n");
    return 0;
}

正解はcaseを複数個並べるというもの。今回だとcase5case6を並べることで動作する。出力は以下。

/*
入力値: 0	1から6までの整数を入力してください
入力値: 1	あなたは一番小さい数字を入力しましたね
入力値: 2	今日は良いことがあるでしょう
入力値: 3	中庸の徳です
入力値: 4	4は幸せの4
入力値: 5	あなたは5もしくは6を選びました
入力値: 6	あなたは5もしくは6を選びました
入力値: 7	1から6までの整数を入力してください
これでおしまいです
 */

ちなみにcase5case6を縦ではなくcase 5: case 6:のように横に並べる場合でも一応動作はした。しかし、色々とサイトを見る限りは縦に書いているので、縦に書くのが無難だろう。

caseを数字ではなく文字にする

最後にcaseの後のconstant-expressionを数字ではなく文字にした場合を考える。

配列という考え方

そこで新たな考え方として「配列」を使用する。配列はpythonでいうlistのようなものと考えている。要素を一括で管理して好きに取り出せる。

配列の定義の方法は複数あるが、今回は以下のように定義する。

char arr[] = {'A', 'B', 'C', 'D'};

[]にすることで=の後の要素の数で自動的に配列を作成してくれる。今回ではA, B, C, Dの4要素からなる配列を作成。

ここで気をつけないといけない点が、文字はシングルクォーテーション'で囲まなければいけないという点。

  • シングルクォーテーション': 文字
  • ダブルクォーテーション": 文字列(文字が集まったもの)

らしい。ここではただの文字として扱いたいのでシングルクォーテーションを使用する。pythonではシングルもダブルも同じなのでここはややこしい。

配列から要素を取り出すときはarr[0]のように、要素のインデックスを指定すればよい。始まりは0から、上の例だとarr[0]'A'に相当する。

caseの事例式を文字にする

#include <stdio.h>

int main() {
    int n;
    char arr[] = {'A', 'B', 'C', 'D'};
    char str;

    for (n = 0; n <= 7; n++) {
        str = arr[n];
        printf("入力値: %d = %c\\t", n, str);

        switch (str) {
            case 'A':
                printf("Aが出力\\n");
                break;
            case 'B':
                printf("Bが出力\\n");
                break;
            case 'C':
                printf("Cが出力\\n");
                break;

            default:
                printf("A, B, C以外が出力\\n");
                break;
        }
    }
    printf("これでおしまいです\\n");
    return 0;
}

このコードでは予め作成したarr配列の中から1要素ずつ取り出し、取り出した要素に応じて出力を変更するというもの。

forの最大値を7に設定しているのは、インデックスが配列の要素数を超えた場合の挙動を知るため。pythonでは要素数を超えるとエラーが出る。

出力は以下。

/*
入力値: 0 = A	Aが出力
入力値: 1 = B	Bが出力
入力値: 2 = C	Cが出力
入力値: 3 = D	A, B, C以外が出力
入力値: 4 = 	A, B, C以外が出力
入力値: 5 =
 */

謎すぎる。インデックスが0から3、すなわちAからDまでは予想通りの出力である一方、インデックスが4以降は謎。一応4には空白のようの記号が入っているものの、5では空白が出力されず、さらに6以降は何も出力されない。

これはどうやらC言語の特性らしい。Cはなるべくプログラマのやりたいことを妨げない方針らしく、インデックスを超えてもコンパイルエラーにはならない。しかし、何が起こるかがわからないらしい。

なのでインデックスを超えないように調節する必要がありそうだ。

時々に応じた対応を

今回はC言語のswitch文について解説した。pythonではifしかない(と思っている)ので使い分けができるのは、脳のトレーニングにもなるしコードの最適化にもつながるだろう。

ただ、複数条件の追加時にcaseが重なったりするのが煩わしいと思う。何かいい書き方があるかもしれないのでまた勉強したいと思う。

関連記事

【VScode&拡張機能】python・C・LaTeX...ユーザーのVisual Studio Code拡張機能

続きを見る

【python&独学】独学である程度pythonを習得するマインド

続きを見る

関連コンテンツ

スポンサーリンク

Amazonのお買い物で損したない人へ

1回のチャージ金額通常会員プライム会員
¥90,000〜2.0%2.5%
¥40,000〜1.5%2.0%
¥20,000〜1.0%1.5%
¥5,000〜0.5%1.0%

Amazonギフト券にチャージすることでお得にお買い物できる。通常のAmazon会員なら最大2.0%、プライム会員なら2.5%還元なのでバカにならない。

ゲットしたポイントは通常のAmazonでのお買い物に使えるからお得だ。一度チャージしてしまえば、好きなタイミングでお買いものできる。

なお、有効期限は10年だから安心だ。いつでも気軽にAmazonでお買い物できる。

Amazonチャージはここから出来るで

もっとお得なAmazon Prime会員はこちらから

30日間無料登録

執筆者も便利に使わせてもらってる

スポンサーリンク

  • この記事を書いた人

メガネ

独学でpythonを学び天文学系の大学院を修了。 ガジェット好きでMac×Android使い。色んなスマホやイヤホンを購入したいけどお金がなさすぎて困窮中。 元々、人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂ったために今も人生めちゃくちゃ楽しい。 pythonとガジェットをメインにブログを書いていますので、興味を持たれましたらちょこちょこ訪問してくだされば幸いです🥰。 自己紹介→変わって楽しいの繰り返し

-C言語
-,