プログラム・プロブレム

第五回 条件分岐・繰り返し(C++)


I はじめに

涼(以下S):もうお馴染みですね、涼(すず)です。
初(以下H):初(はじめ)だ。いい加減覚えただろ。
S:今回は条件分岐と繰り返し(ループ)についてですね。
H:一般的な解説だと最初の方にやるのに、また随分と遅くなったもんだな。
S:なんでも「今までのサンプルに必要じゃなかったから」ってことらしいですね。
H:確かに、順序良く進んでる気はするな。前回の例外だけタイミングが微妙だが。
S:…実は、入力で変なモノを入れると例外になると思ってたせいで、この順序になったそうです。
H:そしてサンプルコード書いて試したら、例外にならなかったから慌てたと。
S:結局は予告してたので、順序はそのままでサンプルを差し替えたというわけですね。
H:何と言うか、しょーもない話だな。まあ、ヤツらしいが。
S:というわけで、今更かもしれませんが条件分岐とループです。知ってる人は飛ばしてください。

II ソースコード1

01:// while_and_if.cpp
02:#include <iostream>
03:int main(int argc,char* argv[])
04:{
05:  using namespace std;
06:  int i = 0;
07:  while( i < 1 || 3 < i ) {
08:    cout << "Input time : 1-Morning, 2-Afternoon, 3-Evening" << endl;
09:    cin >> i;
10:  }
11:
12:  if( i == 1 ) {
13:    cout << "Good morning, ";
14:  } else if( i == 2 ) {
15:    cout << "Good afternoon, ";
16:  } else {
17:    cout << "Good evening, ";
18:  }
19:  cout << "world." << endl;
20:
21:  return 0;
22:}
H:あー、英語分かる人には読める感じだな。
S:それでも、いちおう解説しておきましょう。

III 解説1

while

07:  while( i < 1 || 3 < i ) {
08:    cout << "Input time : 1-Morning, 2-Afternoon, 3-Evening" << endl;
09:    cin >> i;
10:  }

H:06行目までは問題無いはずだ。前回までの解説で理解できるようになってる。
S:05行目の「using namespace std;」は04から22行目までのブロック内だけ有効になります。
H:で、07行目だ。新しいのは「while」キーワードだな。
S:「(状況が)~である間はずっと」って意味ですね。
H:つまり、直後のブロック(08、09行目)を条件が成り立っている間繰り返すわけだ。
S:ちなみに、その条件は「while」の後ろにある「i < 1 || 3 < i」の部分です。

OR演算子

H:さて、ここに見慣れない記号「||」がある。これは「OR」を表す記号だ。日本語なら「または」だな。
S:今回の条件の場合は「i < 1 または 3 < i」ということになりますね。
H:「i < 1」か「3 < i」のどちらか(あるいは両方)の条件が満たされれば、全体が満たされた事になる。
S:最初に07行目まで来た時は、i0 に初期化されているので、条件に合致しますね。
H:つまり、その時にはブロック内部が実行される。以後ブロックの最後まで行くたびに条件が再判定されるぞ。

whileループ内部

08:    cout << "Input time : 1-Morning, 2-Afternoon, 3-Evening" << endl;
09:    cin >> i;
S:08行目は文字列を出力するだけです。09行目は i に数値を入力しているところですね。
H:数字以外が入力された時は i には 0 が設定される。例外にはならない。
S:作者さんはここで例外が発生すると勘違いしてたわけです。
H:09行目で入力が行われると、ブロックの最後なので条件の再判定となる。
S:i1~3 のどれでもない時には、もう一回ループすることになりますね。
H:逆に、1~3 のどれかだったら、whileループの条件を満たさなくなるので、次の11行目へ進むわけだ。

条件分岐(if)

12:  if( i == 1 ) {
13:    cout << "Good morning, ";
14:  } else if( i == 2 ) {
15:    cout << "Good afternoon, ";
16:  } else {
17:    cout << "Good evening, ";
18:  }
S:12、14、16行目に新しいキーワードの「if」と「else」が出ています。
H:英語を直訳すると「if」は「もしも~」で、「else」は「他」だな。
S:その意味の通り、「if」は続く条件が満たされた場合にブロックを実行します。
H:条件が満たされなかった場合に、対応する「else」があればそちらのブロックが実行される。
S:今回の場合は12行目で「i == 1」であれば13行目が実行されるわけです。

等値演算子(==)

H:ここでの「==」は「(値が)等しい」って意味だ。「=」だけだと代入命令になるから注意しろよ。
S:C や C++ でよくあるミスのうちの一つが「==」と「=」の打ち間違いなんですよ。
H:人によっては「==」を使う時にはリテラルを先にして「1 == i」みたいに書く場合があるな。
S:こうすると、間違って「1 = i」って書いた時にコンパイルエラーになるんですよね。
H:ちょっとしたテクニックだが、覚えておくと些細なミスにひっかからなくて済むかもな。
S:ちなみに、作者さんは古い人間なのでリテラルが先に来ると違和感があるそうです。
H:そのせいでサンプルでは「i == 1」になってるわけだ。悪い癖だな。

else if

14:  } else if( i == 2 ) {
15:    cout << "Good afternoon, ";
16:  } else {
17:    cout << "Good evening, ";
18:  }
S:さて、14行目では「else if(i == 2)」という表現がありますね。
H:ここでの「else」は12行目での「if」に対応しているぞ。
S:その状況で新しい「if」があるので、12行目が満たされない場合に14行目の if 条件がチェックされます。
H:まさしく「(前の条件の)他で、もしも~」というわけだ。
S:今回は「i == 1」でなくて「i == 2」ならば15行目が実行されます。
H:そして16行目の「else」は直前の if に関連するから、14行目の(else の後の) if が成り立たない場合に実行される事になる。
S:11行目の時点で、while ループを抜けた時の i は 1 か 2 か 3 であることを思い出してください。
H:その状況で 12行目の「i == 1」でもなく、14行目の「i == 2」でもない場合だ。
S:つまり、17行目が実行されるのは「i == 3」の場合ということです。

サンプルと等価なif構造

H:サンプルの12から18行目までは、以下のように書き換えることもできる。
01:  if( i == 1 ) {
02:    cout << "Good morning, ";
03:  } else {
04:    if( i == 2 ) {
05:      cout << "Good afternoon, ";
06:    } else {
07:      cout << "Good evening, ";
08:    }
09:  }
S:12行目にあたるのが01行目、14行目は03と04行目に相当します。
H:そして16行目は06行目にあたるわけだ。
S:条件の判定順序としては、こっちの方が分かりやすいんですが、条件が増えるほどインデントが大きくなるという欠点があります。
H:というわけで、一般的にはサンプルみたいな書き方をされることが多いんだ。

IV ソースコード2

S:なんと、今回はサンプルソースが2個あります。
H:おぉ、内容が2倍ということは2倍お得だな!
S:…というような馬鹿話は置いておきまして、繰り返しの二つ目 for ループにいきましょう。
01:// for.cpp
02:#include <iostream>
03:int main(int argc,char* argv[])
04:{
05:  using namespace std;
06:  int i = 0;
07:  while( i < 1 ) {
08:    cout << "Input positive number:" << endl;
09:    cin >> i;
10:  }
11:
12:  int sum = 0;
13:  for(int n = 1; n <= i; ++n) {
14:    sum += n;
15:    cout << "sum of 1 to " << n << " is " << sum << "." << endl;
16:  }
17:
18:  return 0;
19:}
H:11行目まではサンプル1とほぼ同じだな。
S:ええ。違うのは12から16行目ですね。

V 解説2

for

12:  int sum = 0;
13:  for(int n = 1; n <= i; ++n) {
14:    sum += n;
15:    cout << "sum of 1 to " << n << " is " << sum << "." << endl;
16:  }
H:サンプル1と違う所だけ解説するぞ。
S:12行目…は分かりますね。整数型の変数 sum0 で初期化しています。
H:次が問題だ。新しい「for」キーワードの後ろの括弧の中に「部分A;部分B;部分C」という書き方がされている。
S:部分A は「初期化部」です。最初に一度だけ実行されます。
H:ここでは「int n = 1」だから、整数変数 n1 で初期化するんだ。
S:そして 部分B は「条件部」です。この条件が満たされている限り、forループは続きます。
H:今は「n <= i」になってるから、n がさっき入力された i 以下の間続くわけだ。
S:最後の 部分C は「繰り返し部」です。ループが一度回るたびに実行されます。
H:ここは「++n」だな。これは n1 だけ増やす操作になる。
S:それで、14と15行目がループの中身になります。
H:ループの流れ方だけ見ると「n に 1 を代入」→「n <= i なら中身を実行」→「n += 1」→「n <= i なら中身を実行」→「n += 1」→…となるわけだ。
S:つまり、n1 から i まで 1 ずつ増やしながら繰り返すことになります。

forループ内部

14:    sum += n;
15:    cout << "sum of 1 to " << n << " is " << sum << "." << endl;
H:で、ループの中身だ。簡単だから、ちゃっちゃと行こう。
S:ループが回るたびに変数 sum に、その回の n が加算されてますね。
H:そして、その回の nsum の現在値を表示してる、と。
S:表示内容は、1からその回の n までの合計値となっています。分かりますよね?
H:最後の行には 1から入力された i までの合計値が出るわけだ。試しに「10」を入れると「55」になるはずだ。

VI 終わりに

S:以上、条件分岐とループ2種類の説明でした。どうでしたか?
H:第四回の例外を除いて、ここまで理解すればプログラミングの基本は OK だ。
S:入力、出力、変数の演算、条件分岐、ループの五つですね。覚えてますよね。
H:意外と少ないだろ?後は細かい機能ばっかりなんだぜ。
S:これだけでも簡単な計算プログラムは書けるはずですよ。実用にするには、まだちょっと難しいですが。
H:ここまではホントに重要だから、分からない時はしっかり復習しとくことだな。
S:それでは、また次回にお会いしましょう。

第五回 終了


一覧に戻る