こんな人にオススメ
C言語のswitch
文ってなんなん?if
と何が違うん?
ということで、個人的な疑問のswitch
文について自分で調べてコードを書いてみる。参考にしたのは以前と同様の猫Cこと「猫でもわかるC言語プログラミング」。
以前のVScodeでC言語を初めてみるという記事については以下参照。


目次(クリック・タップでジャンプ)
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
に書かれた内容が該当するcase
のconstant-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) {
の数値の部分の入力が煩わしい。複数選択からの連番作成は例えば以下のようにできる。
) {
を選択cmd
+d
で複数選択- 左カーソルで
n ==
の後まで持っていく - 数値が入っていたら消す
- 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 1
とcase 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
を複数個並べるというもの。今回だとcase5
とcase6
を並べることで動作する。出力は以下。
/* 入力値: 0 1から6までの整数を入力してください 入力値: 1 あなたは一番小さい数字を入力しましたね 入力値: 2 今日は良いことがあるでしょう 入力値: 3 中庸の徳です 入力値: 4 4は幸せの4 入力値: 5 あなたは5もしくは6を選びました 入力値: 6 あなたは5もしくは6を選びました 入力値: 7 1から6までの整数を入力してください これでおしまいです */
ちなみにcase5
とcase6
を縦ではなく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を習得するマインド
続きを見る