switch文による分岐
変数の値に応じて場合分けして複数の処理に分岐したい場合、基本的には前回のとおりif~else if~else if~…~elseというように、「 else if」を必要なだけ連ねて書くことで実現できます。switch文 は、このような条件分岐のための構文で、「 else if」で書くよりも簡潔にプログラムを記述できます。
ただし、条件判断が行えるのは、if文を使う場合の == に相当する値の比較のみで、かつ変数と比較する値は整数の定数でなければなりません。
具体的なswitch文の例をリスト5.11 に示します。
この例では、変数iの値を使ってswitch文で分岐しており、iの値が1 ならば「case 1:」 のラベルへ、2 ならば「case 2:」 のラベルへ飛びます。iの値がどのcaseラベルにも一致しなかった場合は「default:」 のラベルに飛びます。つまり、defaultはif文におけるelseのようなものと考えてよいでしょう。caseやdefaultのラベルに飛んだあとはそのまま順にプログラムが実行され、最後の「break;」 のところでswitch文自体から抜けます。なお、defaultラベルは必要がなければ省略しても構いません。
caseラベルのあとに続く文の最後のbreak がないと、上から順に次のcaseやdefaultラベル以降の文まで実行してしまう ため注意してください。通常は、caseラベルのあとには必ずbreakを書きます。なお、switch文の最後にあるcaseまたはdefaultのラベルについては、breakがなくてもそれ以上実行するプログラムがないため問題ありませんが、あとで新たなcaseラベルを追加する場合を考慮して、すべてのcaseとdefaultラベルにはbreakを入れるもの として覚えた方がよいでしょう。
リスト5.11 switch_test.c
#include <stdio.h>
int
main()
{
int i;
/* i = 1; */
i = 2;
/* i = 3; */
switch (i) {
case 1:
printf("i == 1\n");
break;
case 2:
printf("i == 2\n");
break;
default:
printf("i != 1 && i != 2\n");
break;
}
return 0;
}
図5.4 switch_test(リスト5.11)の実行例
$ gcc -O2 -o switch_test switch_test.c
$ ./switch_test
i == 2
$
caseラベルを並べてOR条件の実現
このように、switch文はラベルにジャンプしたり、breakで終了したりと、ややgoto文のような感じがあり、if文や後述のfor文、while文などくらべて異質に思われるところがあります。caseラベルに対していちいちbreakを付けなければならないのも不可解かも知れません。しかし、この点を逆に利用して、caseラベルを複数並べてOR条件を実現するという使い方があります。
リスト5.12 の例では、「 case 2:」のあとに「break;」がないため、そのまま「case 3:」以降に流れ込みます。「 case 3:」にも同様に「break;」がないため「case 5:」以降に流れ込み、その結果「case 7:」の中の文であるprintf()が実行されます。これは結局、iの変数の値が2または3または5または7の時に同じ処理を行うことになるため、OR条件による条件判断 を行ったことになります。
リスト5.12 switch_prime.c
#include <stdio.h>
int
main()
{
int i;
i = 7;
/* i = 8; */
/* i = 13; */
switch (i) {
case 2:
case 3:
case 5:
case 7:
/* iは10未満の素数 */
printf("i = 10 or not a prime number\n");
break;
}
return 0;
}
図5.5 switch_prime(リスト5.12)の実行例
$ gcc -O2 -o switch_prime switch_prime.c
$ ./switch_prime
i
goto文は普通は使わない
C言語にも、BASIC、FORTRANなどの他のプログラミング言語と同様、goto文 が用意されており、goto文を使って同じ関数内の任意の場所にジャンプすることができます。しかし、C言語では基本的にはgoto文を使用しません。
C言語では通常はif、for、whileなどの制御文を使ってプログラムを記述し、goto文は使用しないようにしてください。goto文を使わなくても書けるのにgoto文を使うのはよくありません。ただし、エラー処理などで、本来のプログラムの流れを中断して別処理に移る場合には、例外的にgoto文を使うこともあります。
goto文は、
goto ラベル名;
と記述し、さらに該当のラベルを同じ関数内に、
ラベル名:
というように、うしろにコロン(:) を付けて記述します。コロン(:)のあとに何も文が続かない場合は、コロンのあとに空文としてのセミコロン(;)が必要になります。
前述のif_test.cをあえてgoto文を使って記述した例をリスト5.13 に示します。この中のlabel1に飛ぶgoto文は、if文の条件が満たされた場合に実行されます。このように、goto文を使ったプログラムはアセンブラのプログラムにも似て、内容がわかりにくくなります。もとのif_test.cのように、通常のif~elseを使ってプログラムを記述した方がよいことは言うまでもありません。
リスト5.13 if_goto.c
#include <stdio.h>
int
main()
{
int i;
i = 5;
/* i = 4; */
if (i != 5) goto label1;
/* i == 5 だった場合の処理 */
printf("i == 5\n");
goto label2;
label1:
/* i != 5 だった場合の処理 */
printf("i != 5\n");
label2:
return 0;
}