条件分岐

これまで扱ってきたプログラムは順次実行のみ、すなわち、上から下に一本道で進むプログラムであった。今回は、条件に応じて実行内容を切り替える「条件分岐」について説明する。

プログラムの処理手順の基本は順次実行、条件分岐、繰り返し(次々回で説明)の3つである。どんな複雑な処理手順でもこれらの組み合わせで成り立っている。

条件分岐のごく簡単な例

次のようなプログラムを書くことを考えてみよう:

宝箱が3つあり、1つは罠であるとする。どれを開けるか選ばせ、罠の宝箱を開けたら「罠だった」とメッセージを表示する。

scanf関数で整数値以外の値を読み取る方法は説明していないので、宝箱に番号を付けて指定させることにしよう。そして、プログラムを例えば次のように言い換えてみる:

1〜3の番号の書かれた宝箱があり、1と書かれた宝箱は罠であるとする。どれを開けるか番号を入力させ、入力された番号が1であれば「宝箱は罠だった」とメッセージを表示する。

簡単のため、1〜3以外の値は入力されないものとする。

ここで「入力された番号が1であれば」をプログラムで書くためには、if文を使う。具体的には、このプログラムは次のように書ける:

/*****
    treasure.c
    宝箱を開けてみる
    M.Minakuchi
*****/

#include <stdio.h>
#include <stdlib.h>

int main() {
    int box;  // 選んだ宝箱の番号

    printf("宝箱が3つある!どれを開けますか?(1か2か3): ");
    scanf("%d", &box);

    if (box == 1)  printf("宝箱は罠だった\n");

    exit(0);
}

練習:上のプログラムを入力、コンパイル、実行して動作を確認しよう。コメントや表示メッセージはこの通りでなくてもよい。入力値は1、2、3のそれぞれで試すこと。

ここでポイントとなるのは

if (box == 1)  printf("宝箱は罠だった\n");

の箇所である。if文の基本的な文法は次のようになっている:

if (条件式) [条件を満足したときに実行される式];

上のプログラムで当てはめると、
条件式は box == 1
条件を満足したときに実行される式はprintf文
となっている。

このプログラムの処理の流れを図示すると次のようになる:

これはフローチャートと呼ばれる図の描き方である。教科書でも使用されている。具体的な書き方は「フローチャート」で検索すると説明ページがすぐに見つかるだろう。

条件式の == に注意!! == は比較演算子(または関係演算子)の一つで、左辺と右辺の値が等しいかどうかを判定するために使う。代入演算子 = と間違わないように!!

【注意!!】C言語では=と==を間違えて書いてしまってもコンパイルが通ってしまう。この間違いを見つけるには実行してみて意図したとおりに動作するかどうかを確かめるしかない。

【上記の高度な補足】C言語では比較演算子の判定結果は、正しい場合(真)は1、正しくない場合(偽)は0という整数値で表されている。また、if文の条件式は、0以外なら真として扱われることになっている。一方、代入文=の実行結果は代入した値となるという決まりがある。このため、条件式のところに代入文を書いてしまっても、なんらかの値が条件として判定されるのでコンパイルエラーにならない。これはC言語が作られた時代が古かったため仕方の無いことである。なお、条件式の結果の値(0または1)を計算に使うようなプログラムは、意図しない不具合の原因になりがちなので通常は書くべきではない。

練習:box == 1の部分をbox = 1と変えてみて、どうなるか確かめよう。

練習:罠の宝箱を2番に変更してみよう。

複数文への条件分岐(ブロック)

上記の例題で1番の宝箱を選んだ場合に、「宝箱は罠だった」というメッセージだけでなく「敵が現れた」というメッセージも表示したい、とする。1つのprinft関数で一度にメッセージを表示することは可能だが、ここでは2つのprintf関数で分けて表示するとしよう。

先ほどのプログラムのif文を使うと、次のように書ける:

/*****
    treasure.c
    宝箱を開けてみる
    M.Minakuchi
*****/

#include <stdio.h>
#include <stdlib.h>

int main() {
    int box;  // 選んだ宝箱の番号

    printf("宝箱が3つある!どれを開けますか?(1か2か3): ");
    scanf("%d", &box);

    if (box == 1)  printf("宝箱は罠だった\n");
    if (box == 1)  printf("敵が現れた\n");

    exit(0);
}

これでも間違いではないが、毎回if文で同じ条件を判定するのも間抜けな感じがする。

このような場合、C言語では複数の実行文を1つにまとめる{ }を使うとよい。if文の場合、書き方は次のようになる({と}の間の式はいくつあってもよい):

if (条件式) {
    [条件を満足したときに実行される式1];
    [条件を満足したときに実行される式2];
    [条件を満足したときに実行される式3];
    .....(以下省略)
}

練習:上記のプログラムを{ }を使った書き方に修正しよう。

このプログラムの処理をフローチャートで描くと次のようになる:

ブロックとインデント

{と}で囲まれた範囲をブロックblockと呼ぶ。main関数の{と}も同様である。ブロックは複数の処理(実行文)をひとかたまりにして扱う意味がある。このような構造を視覚的に分かりやすくするために、ブロック内を字下げ(インデント)して書くのが慣習となっている。例えば、

    if (box == 1) {
    printf("宝箱は罠だった\n");
    printf("敵が現れた\n");
    }

だと、if文の条件が成立したときにどこが実行されるのか分かりにくい(この例では2つしかないので見間違うことはないかもしれないが、何行にも渡るとややこしくなってくる)。

あるいは、次のようなプログラムを書いてはいけない。間違いの元であるし、プログラミングが理解できていないと白状しているようなものである。

    if (box == 1) {
  printf("宝箱は罠だった\n");
     printf("敵が現れた\n");
   }

そこで、

    if (box == 1) {
        printf("宝箱は罠だった\n");
        printf("敵が現れた\n");
    }

このように字下げをしておく。字下げの量(何文字分スペースまたはタブを入れるか)は2文字、4文字、8文字などの流派があるが、自分で見やすいと思う字数で統一するとよい。Emacsなどのエディタでは、拡張子が.cのファイルを編集している場合はC言語のプログラムと解釈して、自動的に字下げを合わせてくれる機能があるので活用するとよい。

Emacsの場合、もし字下げが正しくなくなった場合はTabキーを押すと、その行のインデントを直してくれる。

もしインデントがおかしい場合、{や}を書き忘れているなどの間違いをしていることがある。このようにして「変だな」と思ったら書き間違えてないかよく見るとよい。同様に、コメントや文字列などは色付きで表示されるので普段と雰囲気が違っている場合は何か書き間違えている可能性がある。

{ }を書き忘れるとどうなるか?例えば次のプログラムで考えてみよう。

    if (box == 1)
        printf("宝箱は罠だった\n");
        printf("敵が現れた\n");

練習:実際に実行してみてどうなるか確認しよう。

{ }が無いので、if文の条件が満足されるときに実行される文は次のprintf文だけとなる。そのため、2つめのprintf文はif文に無関係に、常に実行されることになる。このような間違いを防ぐために、if文では常に{と}を使って書く、というように習慣づけるとよいだろう。

私の場合、処理が1行だけの場合でも、後から修正する可能性が低く処理内容が一目瞭然な場合は上記の例のようにif文の後ろにつなげて書いてしまうようにしている。何にしても、読みやすいと思える書き方で、プログラム全体で同じように書くのがポイント。

else さもなければ

宝箱の例題をさらに変えて、下線部の内容を追加してみよう:

1〜3の番号の書かれた宝箱があり、1と書かれた宝箱は罠であるとする。どれを開けるか番号を入力させ、入力された番号が1であれば「宝箱は罠だった」「敵が現れた」とメッセージを表示する。それ以外の番号であれば「あなたは宝を手に入れた」とメッセージを表示する。

ここまでのif文では条件が成り立った場合に実行される分岐を書いていたが、elseを組み合わせて「条件が成り立たなかった」場合の処理も書くことができる。書き方は次のようになる:

if (条件式) {
    [条件を満足したときに実行される式1];
    [条件を満足したときに実行される式2];
    [条件を満足したときに実行される式3];
    .....(以下省略)
} else {
    [条件を満足しなかったときに実行される式1];
    [条件を満足しなかったときに実行される式2];
    [条件を満足しなかったときに実行される式3];
    .....(以下省略)
}

条件を満足したときに実行される式も条件を満足しなかったときに実行される式も、1つしかない場合は{ }は省略可能であるが、間違いの元となりやすいので常に{ }を書くことをお薦めする。

elseは常にifと組み合わせになっている必要がある。elseだけを書くことはできない。

練習:if-elseを使って、上記のプログラムを書いてみよう。

このプログラムの処理をフローチャートで描くと次のようになる:

比較演算子

条件を判定するための比較演算子は次の6種類がある:

== 左辺と右辺の値が等しい
!= 左辺と右辺の値が異なる
> 左辺が右辺より大きい
>= 左辺が右辺より大きいか等しい
< 左辺が右辺より小さい
<= 左辺が右辺より小さいか等しい

== と != 、> と <= 、< と >= は互いに補完し合う関係にあることに注意。

練習:何か整数値を入力させ、入力された値の絶対値を表示するプログラムabsolute.cを作成せよ。

【実行例(下線の部分は入力した整数値の例)】
$ gcc -o absolute absolute.c
$ ./absolute
input number: 123
123
$ ./absolute
input number: -456
456

絶対値の求め方を考えてみると、値が正か0の場合はそのままでよく、負の場合は符号を反転(マイナスをプラスに変換)させればよい。すると、例えば次のようなプログラムを作れば良いことになる(変数名は例。他の名前の変数でもよい):

1) 何か整数値を入力させ変数numberに格納する。
2) 変数numberの値が負の場合は符号を反転させた値を新たな変数numberの値とする。
3) 変数numberの値を表示する。

符号を反転させるには、代入文を使って

number = -number;

と書ける。あるいは、

number *= -1;

でもよい(それぞれ意味を考えてみよう)。

練習:処理の流れをフローチャートで描いてみよう。

練習:absolute.cを完成させよ。

基本的な条件分岐を使った課題

課題:手持ちの金額と、ある品物1個の値段(単価)と、買いたい個数を入力させ、買える場合は「買える。おつりは○○円。」、買えない場合は「買えない。××個までなら買える。」と表示するプログラムshopping.cを作成せよ。ただし、入力される値は0より大きい正の整数であるとする(変な値を入力された場合は考慮しなくてよい)。

【実行例(下線部は入力例)】
$ gcc -o shopping shopping.c
$ ./shopping
手持ちの金額: 1000
単価: 230
個数: 3
買える。おつりは310円。
$ ./shopping
手持ちの金額: 1000
単価: 200
個数: 5
買える。おつりは0円。
$ ./shopping
手持ちの金額: 1000
単価: 230
個数: 5
買えない。4個までなら買える。

腕に覚えのある人は、まず上の説明だけで考えて作ってみて欲しい。どこから手をつけてよいか分からない人は、次のように考えてみよう(これ以外の処理方法で作成しても、正しく動作するのであれば構わない):

課題:手持ちの金額と、ある品物1個の値段(単価)と、買いたい個数を入力させる。次に、買おうとしている品物の合計金額を計算する。手持ちの金額が品物の合計金額と同じか多い場合は、おつりを計算し、「買える。おつりは○○円。」と表示する。そうでない場合(手持ちの金額が品物の合計金額より少ない場合)は買える最大の個数を計算し、「買えない。××個までなら買える。」と表示する。

さらに、どのように計算してよいか分からない人は、次のヒントを見て考えてみよう:

ヒント:
買おうとしている品物の合計金額 = 単価 × 個数
おつり = 手持ちの金額 - 買おうとしている品物の合計金額
買える最大の個数 = 手持ちの金額 / 単価 (整数どうしの割り算なので余りは無視される)

提出期限:6/16(月) 13:15

条件分岐の応用

比較演算子は値の大小関係しか判断できない。ところがコンピュータのソフトウェアは様々な判定をしているように見える。しかし、コンピュータは奥底では数字しか扱えない機械である。そこで、人間には一見数字には見えないような現象を数学的に表現して、数値の比較で条件を判定する必要がある。

一例として、2次元で描かれる2つの物体がぶつかるかどうかを判定する方法を考えてみよう。簡単のため、それぞれの物体は円で表されるとする(つまり、中心からどの方向にも同じ大きさの物体)。すると、2つの円が「ぶつかる」という状態は「2つの円が互いに重なっている」と言い表せる。「互いに重ならない」状態と「互いに重なる」状態の間に「互いに接する」という状態がある。互いに接している状態を「ぶつかる」とするかどうかは特に決まりはないので、どちらなのか選べばよい。ここでは互いに接している状態は「ぶつかっていない」ものとしよう。

2つの円が「接している」状態は、2つの円の中心の距離が2つの円の半径の和と等しい、と表すことができる。「ぶつかっている」状態は、2つの円の中心の距離が2つの円の半径の和よりも小さい、と表すことができる。

練習:2つの円を円1、円2とし、円1の中心座標を(x1, y1)、半径をr1、円2の中心座標を(x2, y2)、半径をr2とする。この時、円1と円2が「ぶつかっている」条件を数式で書け。

距離を求めるには平方根を使うが、値を比較するだけなら両辺を2乗した値で比較しても同じことになる。平方根を使うには数学用の関数と実数型の変数を使う必要があるが、両辺を2乗することで整数のまま計算することができる。

練習:次のプログラムcheckHit.cをHandyGraphicを使用して作成せよ:
ウィンドウの大きさを400x400とし、円1の中心を(200, 200)、半径を150とする。円2の中心座標と半径を入力させ、円1は塗りつぶし無しで描く(輪郭線の太さは初期状態のままでよい)。円2は、円1と円2が「ぶつかっている」場合は赤色、「ぶつかっていない」場合は青色で塗りつぶして描く。

HandyGraphicを使用する際には
#include <handy.h>
を書くことと、コンパイルにはhgccコマンドを使用することを忘れずに。

条件の組み合わせ

複数の値との比較

最初に出てきた宝箱の練習問題で、3つの宝箱それぞれの内容が異なるようにしてみよう:

練習:1〜3の番号の書かれた宝箱がある。どれを開けるか番号を入力させ、入力された番号が1であれば「宝箱は罠だった」、2であれば「あなたは宝を手に入れた」、3であれば「宝箱は空っぽだった」とメッセージを表示するように、treasure.cを修正せよ。

ここまでの例ではif-elseを使って、条件が成立した場合と成立しなかった場合の2つに処理を分岐させた。それに対し、この例では処理を3つに分岐させなければならない。

この練習問題の場合は実は簡単にプログラムできる。

if (box == 1)  printf("宝箱は罠だった\n");
if (box == 2)  printf("あなたは宝を手に入れた\n");
if (box == 3)  printf("宝箱は空っぽだった\n");

実行文が1行だけなので{ }を使わずに書いているが、最初のうちは{ }を書いた方が間違いがないだろう。

宝箱は1か2か3のいずれかなので、このように条件文を3つ連続して書けばいずれかの条件に該当する。該当する条件以外の条件には該当しないことに注意。

このように整数値に応じて処理を振り分ける場合、if文を連ねて書くよりも、最後に紹介するswitch-case文を使った方が読みやすくなる。

値の範囲での条件分岐

値の範囲を指定する際に、それぞれの条件がお互いに重複しない範囲として比較演算子を使って書ける場合は、上の例と同じようにif文を連ねるだけで済む。

練習:整数値を入力させ、入力された値が負の場合は「マイナス」、0の場合は「ゼロ」、正の場合は「プラス」と表示するプログラムsign.cを作成せよ。

一方、比較演算子を使って単純に条件を書けない例として、次のような問題を考えてみよう:

整数値を入力させ、入力された値が10以上100未満の場合は「2桁の値」と表示するプログラムtwoDigits.cを作成せよ。

値の範囲は数式では10 <= x < 100のように書くことができるが、C言語ではこのような書き方は使えない。

実はC言語では、
if (10 <= x < 100) printf("2桁の値\n");
と書いてもコンパイルは通ってしまう。しかし、実行させるとxの値に関わらず、常に条件が成立してしまう。
C言語のプログラミングに慣れた人はなぜこうなるか考えてみよう(ヒント:この条件式は、まず10 < xが判定され、その結果の値が100より小さいか判定される。C言語では真は1、偽は0で表される)。

このような場合、2つの不等式に分けて考える必要がある。つまり、10 <= x < 100は、10 <= xが成立しており、さらに(かつ)、x < 100が成立している、と考える。

ある条件が成立している時に、さらに別の条件が成立しているかどうかを判定する方法の一つは、if文の中にif文を書く方法である。書き方としては次のようになる:

if (条件1) {
    if (条件2) {
        [条件1と条件2が共に満足されたときに実行される式1];
        [条件1と条件2が共に満足されたときに実行される式2];
        [条件1と条件2が共に満足されたときに実行される式3];
        ....
    }
}

練習:10 <= x < 100 を判定する条件文を書いてtwoDigits.cを完成させよう。

なお、この書き方は特別な書き方ではなく、単にif文を組み合わせただけにすぎないことに注意。else節も加えて、他の部分も全部書いてみると次のようになる:

if (条件1) {
    [条件1が満足されたときに実行される式1];
    [条件1が満足されたときに実行される式2];
    ....
    if (条件2) {
        [条件1と条件2が共に満足されたときに実行される式1];
        [条件1と条件2が共に満足されたときに実行される式2];
        ....
    } else {
        [条件1が満足され、条件2が満足されなかったときに実行される式1];
        [条件1が満足され、条件2が満足されなかったときに実行される式2];
        ....
    }
    [条件1が満足されたときに実行される式3];
    [条件1が満足されたときに実行される式4];
    ....
}

条件1が満足されなかった場合は条件1に対するelse節に書けばよいので、条件1と条件2の真偽の組み合わせ4パタンを網羅することができる。

条件の組み合わせは、ここで説明したようにif文の組み合わせでも書けるが、後で説明する論理演算子を使って書くこともできる。

段階的な条件分岐

標準体重(健康的であるとされる体重)は簡易的に次の式で計算できる。

標準体重[kg] = 身長[cm] - 105

身長と体重を入力させ、次のように肥満度をチェックするプログラムweight.cを作成せよ。

体重が標準体重の1割増より重い場合:太りすぎのメッセージを表示する
体重が標準体重の1割増〜1割減の範囲の場合:適切のメッセージを表示する
体重が標準体重の1割減より軽い場合:やせ過ぎのメッセージを表示する

なお、整数型のみで計算するので、1割増、1割減は小数点以下は切り捨てでよい(計算結果を整数型の変数に代入すると自動的にそうなる)。例えば、標準体重が69kgのとき、正確には1割増は75.9kg、1割減は62.1kgであるが、整数型で計算するとそれぞれ75kg、62kgとなる。

【実行例(下線部は入力例)】
$ gcc -o weight weight.c
$ ./weight
身長: 175
体重: 68
ちょうどよいです。
$ ./weight
身長: 175
体重: 78
太りすぎです。
$ ./weight
身長: 175
体重: 58
やせ過ぎです。

なお、標準体重の1割増、1割減は厳密に整数型のみで計算するには次のようにして計算するのがよい。
[標準体重] * 110 / 100
[標準体重] * 90 / 100

[標準体重] * 1.1 や [標準体重] * 0.9 とした場合でも自動的に整数型に変換されるので特に問題はないが、小数点以下が自動的に切り捨てられてしまっていることは意識しておく必要がある。

練習:体重の範囲を数直線で描いてみよう。

数直線で図示すると、それぞれの範囲(条件)は重複していないことが分かる。重複していないのだから、個別にif文を使って次のように書ける:

if ([体重] > [標準体重の1割増]) {
    [太りすぎのメッセージを表示];
}
if ([体重] <= [標準体重の1割増]) {
    if ([体重] >= [標準体重の1割減]) {
        [適切のメッセージを表示];
    }
}
if ([体重] < [標準体重の1割減]) {
    [やせ過ぎのメッセージを表示];
}

これでも間違いではないが、条件を整理すればもう少し簡潔に書ける。まず、2つめのif文の条件は、1つめのif文の条件が成り立たなかったときに該当することに着目すると、else節を使って書き直せる。

if ([体重] > [標準体重の1割増]) {
    [太りすぎのメッセージを表示];
} else {
    if ([体重] >= [標準体重の1割減]) {
        [適切のメッセージを表示];
    }
}
if ([体重] < [標準体重の1割減]) {
    [やせ過ぎのメッセージを表示];
}

次に、最後のif文の条件は、else節の中に移動させたif文の条件が成り立たなかったときに該当する。最初のif文の条件と最後のif文の条件は同時に成立しないので、次のように書き直せる。

if ([体重] > [標準体重の1割増]) {
    [太りすぎのメッセージを表示];
} else {
    if ([体重] >= [標準体重の1割減]) {
        [適切のメッセージを表示];
    } else {
        [やせ過ぎのメッセージを表示];
    }
}

if-else節は全体で1つの文として扱うことができるので、1つめのelse節の{ }は省略することができ、次のように書き直せる。

if ([体重] > [標準体重の1割増]) {
    [太りすぎのメッセージを表示];
} else if ([体重] >= [標準体重の1割減]) {
    [適切のメッセージを表示];
} else {
    [やせ過ぎのメッセージを表示];
}

このように書くと条件がすっきりして振り分け方法が明確になる。簡潔に書くことはプログラムのミスを防ぐ意味で重要である。形式的には、else if という構文として解説されることがあるが(教科書など)、上記説明したとおりif-elseの組み合わせに過ぎない。

2つめの条件は、1つめの条件が成り立たなかった場合にのみ判定されることに注意。

練習:説明したような条件文の組み合わせを使って、weight.cを完成させよ。

論理演算子

不等式で 10 <= x < 100 で表される範囲は、10 <= x かつ x < 100 と考えて、if文の組み合わせで書けることは説明した。では、x < 10, 100 <= x 、つまり、x < 10 または 100 <= x で表される範囲はどうだろうか?

x < 10 と 100 <= x はどちらが成立しても同じ処理を実行するのだから、if文を使って次のように書ける:

if (10 < x) {
    [条件が成立したときに実行する処理]
}
if (100 <= x) {
    [条件が成立したときに実行する処理]
}

[条件が成立したときに実行する処理]は同じ内容であることに注意。

これまでに出てきた比較演算子とif文だけを使って「または」を実現するにはこのように書くしかないが、一見無関係な条件が並べて書かれているように見えてしまったり、条件が成立したときに実行する処理を同じように書かなければならないため、プログラムにミスが生じやすい。

なお、このようなミスを防ぐには「ややこしいな」と感じた場所には極力コメントで説明を書いておくべきである。

そこで、複数の条件式を組み合わせる、論理演算子を使う。基本となる論理演算子は次の3つである。

![条件式1]
[条件式1]でない(NOT、否定)
[条件式1]が真の場合偽、偽の場合真

[条件式1] && [条件式2]
[条件式1]かつ(AND、論理積)[条件式2]
[条件式1]と[条件式2]が共に真の場合真、それ以外の場合偽

[条件式1] || [条件式2]
[条件式1]または(OR、論理和)[条件式2]
[条件式1]と[条件式2]のどちらかが真の場合真、共に偽の場合偽

&&と||は2個連続で書くことに注意。1個だけの&や|は別の意味の演算子になってしまう(コンパイルエラーにはならない)。

それぞれを図示すると次のようになる:

論理演算子を使うと、10 <= x < 100 と x < 10, 100 <= x はそれぞれ次のように書ける。

if (10 <= x && x < 100) {
    [条件が成立したときに実行する処理]
}
if (x < 10 || 100 <= x) {
    [条件が成立したときに実行する処理]
}

評価の優先度は比較演算子の方が論理演算子よりも高いので、&& や || の両辺の比較式が先に評価される。分かりにくければ、
(10 <= x) && (x < 100) のように、()を書くとよいだろう。

不等式は、例えば 10 <= x を x >= 10 と書いても意味は同じである。分かりやすい書き方を選べばよい。私は範囲を記述する場合は不等式と同じになるように書くようにしている。但し、書き方によって若干実行速度が速くなったり遅くなったりすることがある。これは極限状態のプログラムを書かなければならないときに気をつければよいことであって、通常は読みやすさを優先して書くべきである。

switch-case文(教科書4.1節)

宝箱の例のように、ある変数や計算結果の値に応じて処理を振り分ける場合、switch-case文という文法が用意されている。基本的な書き方は次のようになる:

switch (整数式) {
    case 整数定数1:
        実行式1_1;
        実行式1_2;
        ....
        break;
    case 整数定数2:
        実行式2_1;
        実行式2_2;
        ....
        break;
    ....
    ....
    default:
        実行式n_1;
        実行式n_2;
        ....
}        

switchの後の()内の値に一致するcase文の箇所に処理が飛び、その次に書かれている実行式が順に実行される。一致するcase文が無い場合はdefault:に飛ぶ。default:は特にすることがなければ省略可能であるが、念のため書いておく方がよいだろう。break;に達したらswitch文の{に対応する}の次に移動する(途中の処理を飛ばす)。case文の整数定数の後ろは:(コロン)であることに注意!!

break;を省略すると、処理を中断せずに次のcase文の次に書かれている実行文を続けて実行することになる。プログラムによってはそのような書き方をする場合もあるが、break;を意図的に省略したことをコメントで必ず書いておくべきである。

switchとcaseを同じ位置に揃えるインデントのしかたや、caseやdefaultの:の後に最初の実行式を書くなど、書き方は様々なバリエーションがある。自分で見やすいと思う書き方を選べばよい。

宝箱の例をswitch-case文で書くと次のようになる:

switch (box) {
    case 1:
        printf("宝箱は罠だった\n");
        printf("敵が現れた\n");
        break;
    case 2:
        printf("あなたは宝を手に入れた\n");
        break;
    case 3:
        printf("宝箱は空っぽだった\n");
        break;
    default:
        // 何もしない
}

このような条件分岐はif-else if-elseを使っても同じように書けるが、switch-caseを使った方がプログラムの意図をはっきりさせることができる。初心者には少々ややこしいが積極的に使ってみて覚えておこう。

switch-case文を使えないケースとしては、値の範囲で条件分岐させたい場合や、変数や計算式が実数型の場合などがある。

条件の組み合わせを使う課題

課題:まず円の中心座標を入力させる。大きさ600x400のウィンドウを開き、左下の座標が(150, 100)、幅が300、高さが200の長方形を描く(塗りつぶしでなくてよい)。入力された中心座標に半径50の大きさの円を描くとして、円の中心が長方形内の場合は赤色で、長方形の線上か外の場合は青色で塗りつぶして描く(輪郭は描いても描かなくてもよい)プログラムcheckArea.cを作成せよ。

【実行例(下線部は入力例、それぞれの表示は順に下図の通り)】
$ hgcc -o checkArea checkArea.c
$ ./checkArea
x: 300
y: 200
$ ./checkArea
x: 160
y: 180
$ ./checkArea
x: 150
y: 160
$ ./checkArea
x: 140
y: 140

腕に覚えのある人は、まず上の説明だけで考えて作ってみて欲しい。どこから手をつけてよいか分からない人は、次のように考えてみよう:

課題:次の手順で実行するプログラムcheckArea.cを作成せよ。
- 円の中心座標を覚えておくための整数型の変数x, yを宣言する。
- xとyの値をそれぞれ入力させる。
- 大きさ600x400のウィンドウを開く。
- 左下の座標が(150, 100)、幅が300、高さが200の長方形を描く(塗りつぶしでなくてよい)。
- xの値が150 < x < 300450の範囲で、かつ、yの値が 100 < y < 200300の範囲の場合は塗りつぶし色を赤に、そうでない場合は青に設定する。(6/11訂正、範囲の値が間違っていました)
- 中心が(x, y)、半径が50の塗りつぶし円を描く(輪郭は描いても描かなくてもよい)
- HgGetChar();で入力を待つ(プログラムが終了してしまわないようにするため)

if文の組み合わせでも、論理演算子を使った条件式でも、どちらでもよい。

追加ヒント:「xの値が150 < x < 450の範囲で、かつ、yの値が 100 < y < 300の範囲の場合は塗りつぶし色を赤に、そうでない場合は青に設定する。」の部分は、次のような手順に分けると良いと思います(これ以外の方法でも構いません)。

提出期限:6/19(木) 24:00