苦しんで覚えるC言語 8.3 番号による場合分け  P159 – P165

番号と対応させる処理

C言語にはif文での分岐処理と同等の分岐処理が他にもあります。
参考書の例を見ながら解説していきます。

番号名前性別
1野比のび太男性
2源静香女性
3剛田武男性
4骨川スネ夫男性

番号の欄の数値を判定処理の値として分岐処理を書いてみます。

#include <stdio.h>

int main(void)
{
    int no;
    scanf("%d",&no);

    if(no == 1)
    {
        printf("野比のび太\n");
    }else if(no == 2)
    {
        printf("源静香\n");
    }else if(no == 3)
    {
        printf("剛田武\n");
    }else if(no == 4)
    {
        printf("骨川スネ夫\n");
    }else
    {
        printf("そんな番号の人はいない\n");
    }

    return 0;
}

これまで参考にしてきたif文の書き方と変わらず、上記表の「番号」の項目に記載の値に応じた名前をprintf関数で表示をしている処理となります。
単純に、1かどうか?違うなら2かどうか?・・・最終4まで確認した後、1~4以外の値だった場合は、最後のelse文の処理である”そんな番号の人はいない”に到達することになります。
ここでは表の番号項目の値は1~4になっているので、この処理に来ることはありません。

これを別の構文であるswitch文で書くことができます。

switch(条件式)
{
    case 数値:
        実行文;
        break;
    case 数値:
        実行文;
        break;
}

switchと書き出して、( )内に分岐判定をさせたい条件式を書きます。
次行にcaseと書き出して、数値:に条件式に格納されている値を記載します。
更に次行の実行文;に、条件式の値と数値が一致した場合の処理を記載します。
最後にbreak;と記載することで、case~breakまでの一連の纏まりで書かれた処理を締めくくります。

プログラムを例に動作のイメージを見てみましょう。

#include <stdio.h>

int main(void)
{
    int no;
    scanf("%d",&no);

    switch(no)
    {
        case 1:
            printf("野比のび太\n");
            break;
        case 2:
            printf("源静香\n");
            break;
        case 3:
            printf("剛田武\n");
            break;
        case 4:
            printf("骨川スネ夫\n");
            break;
    }

    return 0;
}

if文のプログラム例と等価の条件判定処理になります。

動作の流れは以下のイメージです。
①scanf関数でキーボードから入力された数値データをnoという変数に格納します。
②switch文にてno変数に格納された値がいくらなのか?を判定処理にかけます。
③4つ書かれたcase文が上から順に判定されます。
 最初のcase文の指定値である 1 がnoに格納されているか?
 no == 1であれば、case 1のprintf関数(野比のび太)が表示処理されます。
④最初のcase文の指定値である 1 がnoに格納されていなければ、
 次のcase文の指定値である 2 がnoに格納されているか?を判定します。
 no == 2であれば、case 2のprintf関数(源静香)が表示処理されます。

こんな感じでno変数の中身がcase文の指定値に一致するものと出会うまで、上から順番にcase文の指定値と比較しながら下へ下へ判定を続けていくことになります。
一致する値と出会うと、出会ったcase文の処理文を実行して、それ以下のcase文は実行せずにswitch文を終了させます。

例えば、noに1が格納されている場合、case 1が判定処理で合致することになるので、野比のび太が表示された後、以降のcase 2~case 4は判定処理をせずに、switch文を終了させて次のプログラム処理へ遷移します。
つまり、上記であれば、return 0; がswitch文の次の処理になります。

case文の指定値と合致した後、処理文を実行してswitch文を終了させる。と書きましたが、
この処理に該当するのが、各case文の処理部分の最後に書かれている break; になります。
break; は、ここまで遷移してくるとswitch文を終了させる働きがあります。

case 1~ case 4以外の数値はどうするの?

if文のプログラム例では、末文あたりに ”そんな番号の人はいない\n” というelse文がありました。
switch文ではどうするのでしょうか?それは、以下の様にcase文の末尾にこの様に記載します。

#include <stdio.h>

int main(void)
{
    int no;
    scanf("%d",&no);

    switch(no)
    {
        case 1:
            printf("野比のび太\n");
            break;
        case 2:
            printf("源静香\n");
            break;
        case 3:
            printf("剛田武\n");
            break;
        case 4:
            printf("骨川スネ夫\n");
            break;
    default:
            printf("そんな番号の人はいない\n");
            break;
    }

    return 0;
}

最後に追加した以下の記述がno変数の中身が1~4ではない場合に遷移してくるところになります。

default:
 printf(“そんな番号の人はいない\n”);
break;

caseと書いていた位置に、default : と記載し、他のcase文で指定した値ではないことを明記します。
次行はcase文と同様に、処理させたい内容を記載し、更に次行にbreak;を書いて終了としておきます。

この様に書くと、no変数の中身がcase 1から順番に判定処理を行い、case 4まで遷移したが該当する値が無かった場合は、defaultに遷移してきて ”そんな番号の人はいない” を表示させて修了となります。

同様処理がある場合はまとめる

冒頭の表を使用して以下の様なプログラムを書きました。
番号の値を判定して、性別を表示するものです。

#include <stdio.h>

int main(void)
{
    int no;
    scanf("%d",&no);

    switch(no)
    {
        case 1:
            printf("男性\n");
            break;
        case 2:
            printf("女性\n");
            break;
        case 3:
            printf("男性\n");
            break;
        case 4:
            printf("男性\n");
            break;
    default:
            printf("そんな番号の人はいない\n");
            break;
    }

    return 0;
}

これは、case1、3、4が同じ性別を表示することになっています。
同じ処理が何度も出てくるプログラムコードは、もう少しスマートに書くことが可能です。
例えば以下の様な書き方です。

#include <stdio.h>

int main(void)
{
    int no;
    scanf("%d",&no);

    switch(no)
    {
        case 1:
        case 3:
        case 4:
            printf("男性\n");
            break;
        case 2:
            printf("女性\n");
            break;
    default:
            printf("そんな番号の人はいない\n");
            break;
    }

    return 0;
}

この書き方は、case 1、case 3、case4と書いたswitch文の判定処理にかけられ、
no変数の中身が1、3、4の何れかが格納されている場合は、printf(“男性\n”)の処理が実行され、
次行のbreak処理を経て、switch文の処理は終了となります。

case文は一つずつ記載することも、複数を行を改行して書くことも可能である。と覚えておいてください。

注意!! break文が抜けると処理が変わる

先ほどのプログラムを参考に解説していきます。
case文の処理の最後に必ずbreak文を記載しました。
このbreak文の処理を書き忘れるとどうなるでしょうか?

#include <stdio.h>

int main(void)
{
    int no;
    scanf("%d",&no);

    switch(no)
    {
        case 1:
        case 3:
        case 4:
            printf("男性\n");

        case 2:
            printf("女性\n");
            break;
    default:
            printf("そんな番号の人はいない\n");
            break;
    }

    return 0;
}

case1、case3、case4で “男性” という表示をさせてswitch文は終了でしたが、
breakがない場合は、次のcase 2の判定処理が実行されてしまいます。

break; は、「ここで処理は終了させてね。」という意味があるので、書き忘れた場合は、処理が終わりにならず、上から下へ処理されていくというプログラムセオリー通り、次行に書かれた処理が実行されてしまいます。

上記の場合は、”男性”と表示された後、続けてcase 2の処理である “女性”が表示されて、
case 2の処理最後に書かれた break; でswitch文が終了となります。

混乱が出そうなのは、case 2は no == 2 を判定するのではないのか?
何故、”女性”が表示されるのか?という点だと思われます。

これは、case 1、case 3、case 4の何れかに該当するか?という判定処理に、breakの記述がなくなることで、case 2も追加される形になります。
つまり、case 1、case 2、case 3、case 4の何れかにno変数の値が一致するか?に変わるわけです。
その為、”女性”という表記をさせたくないにもかかわらず、表示が出てしまうので、これはバグになります。

逆に、敢えてbreak;を書かずにcase処理を繋げる場合もあります。
その為、一見するとバグになるのでは!?と思うようなプログラムでも、有識者が分かったうえでトリッキーな記述をしている場合もあるので注意が必要です。

判断力の弱さ

switch文のcaseで判定させることができるのは整数値だけです。
少数値、文字列などは判定itch文のcaseで判定させることができるのは整数値だけです。少数値、文字列などは判定できません。

また、大小の比較もできないので基本的には等価比較( == )、同じ値かどうかだけが判定できるものとなります。

分かりやすいのでswitch文を用いてプログラムされているコードはよく見ます。
ただ、制約もあるため、用途に応じて採用をする必要があります。