このページでは、if文と条件演算子を取り上げます。この2つの機能は、なんらかの条件によって処理を分岐させるものです。処理を分岐させる機能としては、すでに switch文を取り上げていますが、if文や条件演算子は、論理値を用いた、より柔軟な条件での分岐を実現できます。
このページの解説は C++14 をベースとしています。
以下は目次です。要点だけをさっと確認したい方は、「まとめ」をご覧ください。
if文 (if statement) は、条件式📘による分岐構造📘を実現する機能です。条件式を使うので、論理値📘(「論理値」のページを参照)が登場します。
分岐構造を実現する方法として、すでに switch文を取り上げています(「switch文」のページを参照)。switch文でも分岐構造を表現できるものの、あまり自然には書けない場合も多いです。それは、switch文には以下のように多くの制限があるためです。
1番の制限のため、文字列を比較することができません。2番の制限のため、2つ以上の変数の値に応じた分岐を書けません(「a と b の値が同じだったら」など)。3番の制限のため、大小関係の比較ができませんし、4番の制限のため、入力された値と比べるといったことができません。
こういった多くの制限がなく、自由度の高い分岐が実現できる方法が if文です。
if文の文法は次のようになっています。
if (条件式)
// 条件式が true のときに実行する文
【C++17】「条件式」の手前に「初期化文」を置けるようになりました。「初期化文」で宣言した変数を、この if文の中(「条件式」も含む)でだけ使えます。[1]
if文の「条件式」には、bool型の値になるものならば何でも書けます。if (value == 10)
や if (value < value2)
のように、等価演算子📘(「論理値」のページを参照)や関係演算子📘(「論理値」のページを参照)を使った式📘を置いてもいいですし、bool型の値が得られるのならば、単に if (value)
のように変数名だけが置かれてもいいです。
int型や char型の値は bool型に変換できます(「論理値」のページを参照)。std::string型からは変換できないので、(s が std::string型として)if (s)
とは書けません。
if文が実行されるときには、まず「条件式」が評価📘され、bool型の値を得ます。その値が true になったときにだけ「条件式が true のときに実行する文」が実行されます。false になったときには、if文全体が飛ばされます。
for文のときと同様、構文上は「条件式が true のときに実行する文」に書ける文📘は1つだけです。複数の文を書きたいときには、{
と }
によるブロック文📘を導入します。文が1つだけであっても、ブロック文を導入することに問題はありません。つねにブロック文にすることを勧めます。
if文を使ったプログラムの例は次のようになります。入力されたスコアが 100 のときにだけ、追加の文章が出力されます。
#include <iostream>
int main()
{
std::cout << "Please enter the your score.\n";
int score {};
std::cin >> score;
std::cout << "Your score: " << score << "\n";
if (score == 100) {
std::cout << "Great!!\n";
}
}
実行結果:
Please enter the your score.
100 <-- 入力したスコア
Your score: 100
Great!!
Please enter the your score.
50 <-- 入力したスコア
Your score: 50
さきほどの if文では、条件式が true に “ならなかったとき” に実行する文がありません。これは switch文なら、defaultラベルを使って実現できたことです。
if文には、条件式が true にならなかったとき、つまり false になったときにだけ実行する文を書く機能があります。文法は次のようになります。
if (条件式)
// 条件式が true のときに実行する文
else
// 条件式が false のときに実行する文
このように、else というキーワードを用います。プログラムを実行し、if文のところにやってくると、「条件式」が評価され、その値が true になったときにだけ「条件式が true のときに実行する文」が、false になったときにだけ「条件式が false のときに実行する文」が実行されます。つまり、どちらか一方だけしか実行されることはありません。
もちろん、else のところもブロック文を使って、複数の文を書けます。
if (value == 0) {
// 条件式が true のときに実行する文
}
else {
// 条件式が false のときに実行する文
}
なお、false になったときに実行する文だけが必要で、true になったときにすることがない場合、「条件式が true のときに実行する文」を空にできます。このとき {}
でブロック文にしておかないといけません。
// OK
if (value == 0) {
}
else {
std::cout << value << "\n";
}
// エラー。else以下を「条件式が true のときに実行する文」だと判断してコンパイルしようとする
if (value == 0)
else {
std::cout << value << "\n";
}
そもそも、条件式を逆転させて else をなくしたほうが分かりやすい可能性があるので、どちらが理解しやすいか検討するようにしましょう。
// さきほどと同じ意味
if (value != 0) {
std::cout << value << "\n";
}
==
の逆は !=
、!=
の逆は ==
で、これは分かりやすいですが、大小関係の逆は注意しましょう。<
の逆は >=
ですし、>
の逆は <=
です。
else を使った if文のプログラムは次のようになります。入力されたスコアに応じて、合格・不合格を判断します。
#include <iostream>
int main()
{
std::cout << "Please enter the your score.\n";
int score {};
std::cin >> score;
std::cout << "Your score: " << score << "\n";
if (score >= 60) {
std::cout << "Pass.\n";
}
else {
std::cout << "Failure.\n";
}
}
実行結果:
Please enter the your score.
70 <-- 入力したスコア
Your score: 70
Pass.
Please enter the your score.
40 <-- 入力したスコア
Your score: 40
Failure.
else を使って、条件式を満たすときと満たさないときに分岐できるようになりました。しかし、switch文なら3つ以上の選択肢が書けたのですから、まだ if文のほうが劣っている感じがします。
if文でも、3つ以上の処理のいずれかを実行させる分岐構造が作れます。そのためには、else のところに if文を書いて、if と else を繰り返していきます。たとえば、次のようになります。
if (条件式A)
// 条件式Aが true のときに実行する文
else if (条件式B)
// 条件式Aが false で、かつ条件式Bが true のときに実行する文
else if (条件式C)
// 条件式Aと条件式Bが false で、かつ条件式Cが true のときに実行する文
else
// 条件式A、条件式B、条件式Cがいずれも false のときに実行する文
else if
の連鎖はどこまでも続けられます(コンパイラがどこかで限界を設けているかもしれませんが、実用上、気にすることはありません)。最後の1つだけは単体の else
にしてもよく、「結局どれにも一致しなかったとき」に実行する文を記述できます(switch文でいうところの default に当たるもの)。最後の1つも else if
でも構いません。その場合は、「結局どれにも一致しなかったとき」にすることは何もないということになります。
どんなに複雑にみえても、どんなに長大になっていたとしても、上から順に1つずつ条件式が調べられていくイメージを持てば問題ありません。
まず先頭の条件式Aを評価します。これが true なら「条件式Aが true のときに実行する文」を実行したあと、一気に最後まで移動して終了します。false だったなら、次の else if
へ進みます。
else if (条件式B)
では条件式Bを評価して、true なら「条件式Aが false で、かつ条件式Bが true のときに実行する文」が実行されて終了。false なら、次の else if
へ進みます。以下は同様です。
else if
がたくさん並んでいても、条件を満たして実行される文はどれか1つだけです(あるいは、どの条件も満たさなかったうえに単体の else もないため、どれも実行されないか)。
【上級】そのため、早く登場する if文で true になった方が、プログラムの実行速度は速いことになります。
else if
の連続を用いたプログラムは、次のようになります。入力されたスコアに応じて、3つの文字列のいずれかが出力されます。
#include <iostream>
int main()
{
std::cout << "Please enter the your score.\n";
int score {};
std::cin >> score;
std::cout << "Your score: " << score << "\n";
if (score == 100) {
std::cout << "Great!!\n";
}
else if (score >= 60) {
std::cout << "Pass.\n";
}
else {
std::cout << "Failure.\n";
}
}
実行結果:
Please enter the your score.
100 <-- 入力したスコア
Your score: 100
Great!!
Please enter the your score.
70 <-- 入力したスコア
Your score: 70
Pass.
Please enter the your score.
40 <-- 入力したスコア
Your score: 40
Failure.
なお、if
と else if
の条件式はそれぞれ、まったく関係性がないことでも構いません。たとえば、if (value > 0)
の次に登場する条件式が str == "Hello"
であっても構いません。これは、調べる対象が1つに固定されている switch文にはない自由さです。
switch文のように、3つ以上の選択肢が if文でも書けるからといって(そして、他の面でも制約が少ないからといって)、switch文に使い道がないということではありません。「ある値が、いくつかの定数のどれに一致するか」というかたちを取る場面では、switch文で書いた方が意図が明確です。
条件に応じて処理を分岐させるというよりは、「条件に応じた値が欲しい」という場面があります。そういう場合でも if文を使って書けないことはありません。
#include <iostream>
#include <string>
int main()
{
std::cout << "Please enter the your score.\n";
int score {};
std::cin >> score;
std::string judge {};
if (score >= 70) {
= "Pass.";
judge }
else {
= "Failure.";
judge }
std::cout << judge << "\n";
}
実行結果:
Please enter the your score.
70 <-- 入力したスコア
Pass.
入力されたスコアに応じて異なる文字列を、変数 judge に代入しています。これでも目的は果たせますが、いったん、空の状態で宣言してから、値を代入していることが少し気になるところです。こういう作りになっていると、本当にどこかで正しい文字列が代入されるのか(されているか)を気にしなければなりません。できることなら、変数の値は宣言と同時に決まり、そのまま変化しないことが、分かりやすさの観点からは望ましいです(「代入」のページを参照)。
また、judge = ****;
という、同じ目的の同じかたちのコードが重複していることもやや気になります。そうそうあるとは思えませんが、間違って片方だけ別の変数に代入してしまうようなミスが起こるかもしれません。
こういった気になるポイントを解消するために、条件演算子📘 (conditional operator) が利用できます。条件演算子は次の構文で使用します。
? true の場合に実行する式 : false の場合に実行する式 条件式
条件演算子は、オペランド📘が3つある珍しい(C++ では唯一の)演算子です。3つのオペランドを区切るように ?
と :
という2つの記号を使います。
条件演算子を使った式が実行されるとき、まず「条件式」が評価され、true か false を得ます。true だった場合は「true の場合に実行する式」が、false だった場合は「false の場合に実行する式」が評価されます。いずれかの式を評価した結果が、全体としての評価結果になります。
さきほどのプログラムを条件演算子で書き換えると、次のようになります。
#include <iostream>
#include <string>
int main()
{
std::cout << "Please enter the your score.\n";
int score {};
std::cin >> score;
std::string judge {score >= 70 ? "pass" : "failure"};
std::cout << judge << "\n";
}
実行結果:
Please enter the your score.
70 <-- 入力したスコア
pass
これなら、変数 judge は確実に初期化されていると自信をもっていえます。何かを誤る可能性が減っています。
この場合は、変数 judge ももはや不要かもしれません。もしそうであれば、次のように書いてしまえます。構文の解釈の都合上、( )
を補う必要があります。
std::cout << (score >= 70 ? "pass" : "failure") << "\n";
条件によって変数の初期値を切り替えたり、std::cout の文の中で切り替えたりできるのは、条件演算子が結果の値を返してくれているからです。言い換えると、score >= 70 ? "pass" : "failure"
が「式」だからです(式は値を返す)。if文は名前のとおり「文」ですから、こういうことはできないのです(文は値を返さない)。
条件演算子を使う場合、「true の場合に実行する式」や「false の場合に実行する式」のところに1つの式しか書けません。そもそも、すぐに読みづらいコードになってしまいやすいので、単純な式だけで済むように使うべきではありますが、コンマ演算子 (comma operator) を使えば、複数の式を入れ込めます。
コンマ演算子は ,
で表現される演算子で、2つの式を挟むように配置します。
, 式2 式1
まず「式1」が評価され、そのあとで「式2」が評価されます。「式1」を評価した結果の値は捨てられてしまい、「式2」を評価した結果の値が、全体としての値になります。
かなり無理やりな例ですが、次のように条件演算子の「true の場合に実行する式」や「false の場合に実行する式」で、出力を行いつつ、true/false を結果の値にできます。
#include <iostream>
#include <string>
int main()
{
std::cout << "Please enter the your score.\n";
int score {};
std::cin >> score;
bool is_pass {score >= 70 ?
(std::cout << "pass\n", true) :
(std::cout << "failure\n", false)
};
std::cout << std::boolalpha << is_pass << "\n";
}
実行結果:
Please enter the your score.
70 <-- 入力したスコア
pass
true
コンマ演算子をうまく使える場面として for文があります。ループ内で使う変数を2つ以上宣言したいときや、インクリメントなどの操作を複数の変数に対して行いたいときに使えます。
#include <iostream>
int main()
{
for (int i = 0, j = 5; i < 5; ++i, --j) {
std::cout << "i == " << i << ", j == " << j << "\n";
}
}
実行結果:
i == 0, j == 5
i == 1, j == 4
i == 2, j == 3
i == 3, j == 2
i == 4, j == 1
int i = 0, j = 5;
のようにコンマ演算子を使うことによって、同じ型の変数を2つ一気に定義しています。また、++i, --j
のように、ループ1回の終了時の処理に複数の式を記述できています。
for文の外で変数を宣言するときにも同じように書けます。ただしこの場合はコンマ演算子ではなく、単なる文法上の区切りのルールに過ぎません。
#include <iostream>
int main()
{
int i = 0, j = 5; // OK. この , は単なる区切りの文字であってコンマ演算子ではない
// int i {0}, j {5}; // これも OK
std::cout << "i == " << i << ", j == " << j << "\n";
}
実行結果:
i == 0, j == 5
if (b) {...}
のように)
{}
を使ってブロック文にすれば、複数の文を記述できるif (a == 0) {...} else {...}
のように)if (b1) {...} else if (b2) {...}
のように)
a == 0 ? "zero" : "non zero"
のように)
?
の後ろに、満たさないときに実行する式を :
の後ろに書く
新C++編の【本編】の各ページには、末尾に練習問題があります。ページ内で学んだ知識を確認する簡単な問題から、これまでに学んだ知識を組み合わせなければならない問題、あるいは更なる自力での調査や模索が必要になるような高難易度な問題をいくつか掲載しています。
問題の難易度について。
★は、すべての方が取り組める入門レベルの問題です。
★★は、自力でプログラミングができるようなるために、入門者の方であっても取り組んでほしい問題です。
★★★は、本格的にプログラマーを目指す人のための問題です。
次のプログラムを実行したとき、B が出力されるのは、変数 value の値が以下のいずれのときですか? すべて選んでください。
#include <iostream>
int main()
{
int value {};
if (value <= 10) {
std::cout << "A\n";
}
else {
std::cout << "B\n";
}
}
switch文で書かれた次の分岐構造を、if文で書き換えてください。
#include <iostream>
int main()
{
std::cout << "Please enter the integer.\n";
int value {};
std::cin >> value;
switch (value) {
case 0:
std::cout << "A\n";
break;
case 1:
std::cout << "B\n";
break;
case 2:
std::cout << "C\n";
break;
default:
std::cout << "X\n";
break;
}
}
2つの整数の入力を受け取り、大きい方の値を出力するプログラムを作成してください。if文を使う場合と、条件演算子を使う場合とで書いてみてください。
入力されたスコアに応じて、以下のように *
を出力したいとします。
*
を出力して改行する*
を出力して改行する*
を出力して改行するそこで、次のようなプログラムを書きましたが、これは間違っています。その理由を答え、正しいプログラムを書いてください。
#include <iostream>
int main()
{
std::cout << "Please enter the score.\n";
int score {};
std::cin >> score;
if (score < 40) {
std::cout << "\n";
}
else if (score >= 40) {
std::cout << "*\n";
}
else if (score >= 70) {
std::cout << "**\n";
}
else if (score == 100) {
std::cout << "***\n";
}
}
1 から 50 までの整数の中で、4 の倍数のものだけを出力するプログラムを作成してください。ただし、for文と if文を使うようにしてください。
実行結果はこうなります。
4
8
12
16
20
24
28
32
36
40
44
48
「for文」のページで取り上げた電卓プログラム(ソースコードは以下に再掲)を改造して、ゼロ除算を回避するようにしてください。たとえば、“zero divide.” のような文字列を出力するといった対応をしてください。
#include <iostream>
#include <string>
int main()
{
constexpr auto addition = '+';
constexpr auto subtraction = '-';
constexpr auto multiplication = '*';
constexpr auto division = '/';
for (int i = 0; i < 5; ++i) {
std::cout << "Please enter the formula.\n";
int value1 {};
std::string op {};
int value2 {};
std::cin >> value1 >> op >> value2;
switch (op[0]) {
case addition:
std::cout << value1 + value2 << "\n";
break;
case subtraction:
std::cout << value1 - value2 << "\n";
break;
case multiplication:
std::cout << value1 * value2 << "\n";
break;
case division:
std::cout << value1 / value2 << "\n";
break;
default:
std::cout << "The formula is incorrect.\n";
break;
}
}
}
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
![]() |
管理者情報 | プライバシーポリシー |