C言語超入門③ if文とswitch文で条件分岐しよう
if、else、比較演算子、論理演算子、switchを使い、条件によって処理を変える方法を学びます。
「60点以上なら合格。それ以外なら復習」。人ならすぐ判断できますが、プログラムには判断の順番をはっきり書く必要があります。
そのための道具が条件分岐です。今回はifで範囲を判定し、switchで選択肢を分けます。「動いたけれど、境目の値だけ間違う」を防ぐところまで見ていきましょう。
短いコードは、#include <stdio.h>を置いたプログラムのmain内で試します。入力の書き方は前回を参照してください。
1. ifは「条件を満たしたときだけ」
#include <stdio.h>
int main(void) {
int score = 75;
if (score >= 60) {
printf("合格です。\n");
}
printf("判定を終えました。\n");
return 0;
}
合格です。
判定を終えました。
score >= 60は「点数が60以上か」という条件です。ifの丸かっこの中で判断し、当てはまれば波かっこの中へ進みます。
値を55へ変えると、「合格です」は表示されず、「判定を終えました」だけが表示されます。最後の表示はifの外側なので、条件にかかわらず実行するからです。
C言語では、条件の結果が0なら偽、0以外なら真として扱います。比較式は、成り立つと1、成り立たないと0になります。
2. elseで「それ以外」を書く
int score = 55;
if (score >= 60) {
printf("合格です。\n");
} else {
printf("復習して、もう一度挑戦しましょう。\n");
}
elseは「直前のifに当てはまらなかった場合」です。改めてscore < 60と書かなくても、残った場合を受け持ちます。
この例では55が60以上ではないため、下のメッセージだけが表示されます。2つが両方実行されるわけではありません。
3. 3段階ならelse ifを使う
int score = 75;
if (score >= 80) {
printf("よくできました。\n");
} else if (score >= 60) {
printf("合格です。\n");
} else {
printf("復習しましょう。\n");
}
75点のときの流れを追います。
75 >= 80は偽なので、最初の表示はしない75 >= 60は真なので、「合格です」を表示する- 残りの
elseは実行せず、分岐の先へ進む
ここでscore >= 60を一番上に置くとどうなるでしょう。85点も最初の条件に当てはまり、「よくできました」の判定へ届かなくなります。
範囲が重なる条件は、狭い条件を先に置くと考えやすくなります。ただし、それが唯一の書き方ではありません。小さい値からscore < 60、score < 80の順に調べる方法もあります。
ifを別々に書いた場合とは違う
int score = 85;
if (score >= 80) {
printf("80点以上\n");
}
if (score >= 60) {
printf("60点以上\n");
}
これは独立した2つの判断なので、両方表示します。1つの結果だけを選ぶならif / else if / else、条件ごとに追加処理するなら独立したifが向きます。
4. 比較の記号を整理する
| 記号 | 意味 | 60を境にした例 |
|---|---|---|
== |
等しい | score == 60 |
!= |
等しくない | score != 60 |
> |
より大きい | 60自身は含まない |
< |
より小さい | 60自身は含まない |
>= |
以上 | 60自身を含む |
<= |
以下 | 60自身を含む |
特に間違えやすいのが=と==です。if (score = 60)は比較ではなく、scoreを60へ変更する代入になってしまいます。代入した値が0以外なので、条件も真になります。
「コンパイルできたから正しい」とは言えないところが、やっかいですね。-Wall -Wextraなどの警告も見ながら、比較は等号2つと確認しましょう。
MicrosoftのC言語if文の説明では、条件の真偽と分岐の範囲を確認できます。
5. 「かつ」「または」で条件を組み合わせる
| 記号 | 意味 | 例 |
|---|---|---|
&& |
両方を満たす | 0以上、かつ100以下 |
|| |
少なくとも片方を満たす | 0未満、または100より大きい |
! |
真偽を反対にする | 条件を満たしていない |
int score = 75;
if (score >= 0 && score <= 100) {
printf("点数の範囲内です。\n");
}
if (score < 0 || score > 100) {
printf("点数の範囲外です。\n");
}
0 <= score <= 100とは書きません。C言語では左の比較結果が0か1になり、その結果を100以下か調べる形になるため、意図した範囲判定になりません。
条件が長いときは、(age >= 18 && hasTicket) || isStaffのように、意味のまとまりをかっこで示すと読み間違いを減らせます。
左だけで決まれば、右は調べない
&&は左が偽なら右を実行せず、||は左が真なら右を実行しません。これが短絡評価です。
int total = 10;
int count = 0;
if (count != 0 && total / count >= 2) {
printf("平均は2以上です。\n");
}
count != 0が偽なので、0で割る式へ進みません。逆の順番にすると先に割ってしまいます。「危険な処理をしてから確認」では遅いので、確認を左へ置きます。
6. switchでメニュー番号を選ぶ
点数のような範囲ではなく、「1なら開始、2なら設定」と決まった値を選ぶ場合はswitchが読みやすくなります。
int menu = 2;
switch (menu) {
case 1:
printf("ゲームを始めます。\n");
break;
case 2:
printf("設定を開きます。\n");
break;
default:
printf("1か2を選んでください。\n");
break;
}
menuの値に一致するcaseから実行し、breakでswitchを抜けます。どれにも一致しないときがdefaultです。
breakを消すと、次のcaseに書かれた処理へ流れ続けます。これをフォールスルーと呼びます。後ろのcaseと値が一致したからではありません。初心者のメニューでは、各処理の最後にbreakを置く方が分かりやすいでしょう。
C言語のswitchは整数や文字定数などを使います。文字列や、case score >= 60:のような条件式による範囲判定には使いません。
7. 間違いを見つけるには、境目を試す
60点で合格、80点で上の評価なら、59・60・79・80を試します。
| 点数 | 期待する結果 |
|---|---|
| 59 | 復習 |
| 60 | 合格 |
| 79 | 合格 |
| 80 | よくできました |
このような境目の確認を境界値のテストと呼びます。75だけ試すより、>と>=の間違いを見つけやすくなります。
また、if (条件);のように丸かっこの直後へ;を付けると、何もしない文が条件の対象になります。波かっこの中が条件と無関係に動く原因になるので、余分なセミコロンにも注意してください。
8. 練習:正・ゼロ・負を分けよう
-999から999までの整数を1つ入力し、正の数・0・負の数に分けて表示します。入力が数として読めなかったら、計算せず終了してください。
模範解答
#include <stdio.h>
int main(void) {
int number = 0;
printf("integer (-999 to 999): ");
if (scanf("%4d", &number) != 1 ||
number < -999 || number > 999) {
printf("入力を確認してください。\n");
return 1;
}
if (number > 0) {
printf("0より大きいです。\n");
} else if (number == 0) {
printf("0です。\n");
} else {
printf("0より小さいです。\n");
}
return 0;
}
解説
入力を確認した後、まず正かどうか、次に0かどうかを判定します。その両方ではない整数は負なので、最後はelseだけで足ります。
5なら最初、0なら2番目、-5なら最後へ進みます。number >= 0を最初にすると0まで最初の分岐へ入るため、ここでは>を使います。
なお、このscanfは先頭の数値部分を読む練習用です。5abcなど行全体の不正入力を拒否する方法は、最終回の入力処理で扱います。
次の一歩
分岐を書くときは、「どんな値を入れるか」「どれを表示したいか」を先に日本語で書くと、条件へ変換しやすくなります。
次は、同じ判定や表示を何度も行う繰り返しへ進みましょう。