C++超入門③ if文で条件によって処理を変えよう
if、else if、else、比較演算子、論理演算子、switch文を使い、条件によって動きが変わるプログラムを作ります。
点数が75なら合格、55なら復習。入力や値によって動きを変えたいときに使うのが条件分岐です。
ifの形だけなら短いのですが、順番や境目を間違えると、動いているのに結果がおかしくなります。今回は「なぜその分岐に入るのか」を、値を変えながら確認しましょう。
短いコードは#include <iostream>があるプログラムのmain内で試します。変数と入力は前回で扱いました。
1. 条件がtrueなら、その中を実行する
#include <iostream>
int main() {
int score = 75;
if (score >= 60) {
std::cout << "合格です。\n";
}
std::cout << "判定を終えました。\n";
return 0;
}
表示は「合格です」「判定を終えました」の2行です。
score >= 60は「scoreが60以上か」という比較です。成り立てばtrue、成り立たなければfalseという真偽値になります。
scoreを55に変えると、ifの中は飛ばされます。ただし最後の表示は波かっこの外なので、引き続き実行されます。
ifの範囲を決めるのは字下げではなく{ }です。中身が1行でもかっこを省かない方が、後で行を増やすときに間違えにくくなります。
2. elseは「そうでなければ」
int score = 55;
if (score >= 60) {
std::cout << "合格です。\n";
} else {
std::cout << "もう一度復習しましょう。\n";
}
どちらか片方だけが実行されます。最後のelseには条件を付けません。最初の条件に当てはまらなかったすべての場合を担当します。
ここで大切なのは、「elseに進んだとき、何が分かっているか」です。今回なら、すでにscore >= 60が偽なので、60未満だと分かっています。
3. else ifの順番で、結果が変わる
int score = 85;
if (score >= 80) {
std::cout << "とてもよくできました。\n";
} else if (score >= 60) {
std::cout << "合格です。\n";
} else {
std::cout << "復習しましょう。\n";
}
85は80以上なので、最初の表示だけで終わります。後ろのscore >= 60も数学的には真ですが、そこまで調べません。
| 点数 | 最初の比較 | 次の比較 | 表示 |
|---|---|---|---|
| 85 | 真 | 調べない | とてもよくできました |
| 75 | 偽 | 真 | 合格 |
| 55 | 偽 | 偽 | 復習 |
80以上より先に60以上を置くと、85が「合格」に入ってしまいます。一度選んだら後ろへ進まないことを意識して順番を決めます。
ifを2つ並べる場合
独立したif (score >= 80)とif (score >= 60)を続けると、85では両方実行されます。
1つの評価を選びたいなら連続したelse if、当てはまる処理をそれぞれ追加したいなら独立したifです。C++公開標準草案のif文でも、この分岐の関係を確認できます。
4. 比較の記号は「境目を含むか」で覚える
| 記号 | 意味 |
|---|---|
== |
等しい |
!= |
等しくない |
> |
より大きい。境目を含まない |
< |
より小さい。境目を含まない |
>= |
以上。境目を含む |
<= |
以下。境目を含む |
score > 60なら60点は含まれません。60点を合格にしたい場合は>=です。
=は代入、==は比較です。if (score = 60)はscoreを60へ変更してしまい、0以外なので真になります。コンパイルできても意図と違う場合があるため、警告も確認しましょう。
また、if (score >= 60);の余分なセミコロンも注意点です。条件に対応する処理が「何もしない文」になり、その後のまとまりが条件と無関係に動く原因になります。
5. &&・||・!を使う
int age = 19;
bool hasTicket = true;
if (age >= 18 && hasTicket) {
std::cout << "入場できます。\n";
}
&&は「かつ」です。18歳以上であることと、チケットを持つことの両方を満たす必要があります。
||は「または」、!は真偽を反対にします。ここで使う&&や||は論理演算子で、&や|を1つだけ書く演算とは別です。
0から100の範囲は2つの比較にする
if (score >= 0 && score <= 100) {
std::cout << "有効な点数です。\n";
}
0 <= score <= 100とは書きません。C++では左側の比較結果trueまたはfalseを、さらに100と比較する形になるため、期待する範囲判定になりません。
範囲外を調べるなら、score < 0 || score > 100です。「内側はかつ、外側はまたは」と図を思い浮かべると、最初は分かりやすいでしょう。
危険な処理の前に確認する
int total = 10;
int count = 0;
if (count != 0 && total / count >= 2) {
std::cout << "平均は2以上です。\n";
}
&&は左が偽なら右を実行しません。この短絡評価で、0除算へ進む前に止められます。逆の順番だと先に割ってしまうので、順番も処理の一部です。
6. 入力の確認と、評価の判定を分ける
#include <iostream>
int main() {
int score = 0;
std::cout << "点数(0-100): ";
if (!(std::cin >> score)) {
std::cout << "整数として読めませんでした。\n";
return 1;
}
if (score < 0 || score > 100) {
std::cout << "0から100の範囲で入力してください。\n";
return 1;
}
if (score >= 80) {
std::cout << "とてもよくできました。\n";
} else if (score >= 60) {
std::cout << "合格です。\n";
} else {
std::cout << "復習しましょう。\n";
}
return 0;
}
-5や200を、そのまま成績として判定しないようにしています。先に「扱ってよい値か」、その後で「どう評価するか」を分けると、複雑な条件を1つへ詰め込まずに済みます。
このcinは先頭の数値部分を読む方法です。80点など行全体を拒否したい場合は、最終回の入力方法を使います。
7. switchは決まった選択肢に向いている
int menu = 2;
switch (menu) {
case 1:
std::cout << "ゲームを開始します。\n";
break;
case 2:
std::cout << "設定を開きます。\n";
break;
default:
std::cout << "1か2を選んでください。\n";
break;
}
menuと一致するcaseへ進み、breakで抜けます。どれにも当てはまらない場合がdefaultです。
breakを忘れると、次のcaseの処理も続けて実行するフォールスルーが起きます。範囲の比較はif、メニュー番号や列挙型はswitch、という使い分けが最初は分かりやすいでしょう。std::stringをそのままswitchの対象にはできません。
8. 練習:年齢で料金区分を表示しよう
今回は架空の料金ルールです。0〜120歳の整数について、12歳以下を子ども、13〜64歳を通常、65歳以上をシニアと表示します。
模範解答
#include <iostream>
int main() {
int age = 0;
std::cout << "年齢(0-120): ";
if (!(std::cin >> age) || age < 0 || age > 120) {
std::cout << "入力を確認してください。\n";
return 1;
}
if (age <= 12) {
std::cout << "子ども料金\n";
} else if (age >= 65) {
std::cout << "シニア料金\n";
} else {
std::cout << "通常料金\n";
}
return 0;
}
解説
入力を確認してから、12歳以下か、65歳以上かを調べます。その両方ではない値が13〜64歳なので、最後のelseで通常料金になります。
確認用の答えは、12→子ども、13→通常、64→通常、65→シニアです。境目とそのすぐ隣を試すと、<と<=の間違いが見つかりやすくなります。
シニアの条件を先に置く書き方でも、この2つの範囲は重ならないため同じ結果になります。
次の一歩
条件を作る前に、代表的な入力と期待する結果を並べてみましょう。文章で決めたルールを、そのまま比較と分岐へ落とし込む感覚が大切です。