実行時間制限: 0 msec / メモリ制限: 0 KB
補足
この説明を読む前に付録4.ループの裏技repマクロを読んだほうが理解しやすいです。ただし、必須の知識では無いので読まなくても問題ありません。
キーポイント
- for文は繰り返し処理でよくあるパターンをwhile文より短く書くための構文
- 「初期化」→「条件式」→「処理」→「更新」→「条件式」→「処理」→...という順で実行され、条件式が真のとき繰り返し続ける
for (初期化; 条件式; 更新) { 処理 }
- N回の繰り返し処理は次のfor文で書くのが一般的
for (int i = 0; i < N; i++) { 処理 }
- breakを使うとループを途中で抜けられる
- continueを使うと後の処理を飛ばして次のループへ行ける
for文
for文は「N回処理する」というような繰り返し処理でよくあるパターンをwhile文より短く書くための構文です。
3回繰り返すプログラムをwhile文とfor文で書くと次のようになります。
#include <bits/stdc++.h> using namespace std; int main() { int j = 0; while (j < 3) { cout << "Hello while: " << j << endl; j++; } for (int i = 0; i < 3; i++) { cout << "Hello for: " << i << endl; } }
実行結果
Hello while: 0 Hello while: 1 Hello while: 2 Hello for: 0 Hello for: 1 Hello for: 2
for文は次のように書き、条件式が真のとき処理を繰り返し続けます。
for (初期化; 条件式; 更新) { 処理 }
実行される順序は次のとおりです。
はじめのプログラムのfor文が実行される様子を表したのが次のスライドです。
forとwhileの対応関係
for文とwhile文の対応関係を見てみましょう。
int i = 0; // 初期化 while (i < 3 /* 条件式 */ ) { cout << "Hello while: " << j << endl; // 処理 i++; //更新 }
for (int i = 0 /* 初期化 */ ; i < 3 /* 条件式 */ ; i++ /* 更新 */) { cout << "Hello for: " << i << endl; // 処理 }
処理される順序はwhile文で書いたときと全く同じで、「初期化」→「条件式」→「処理」→「更新」→「条件式」→「処理」→...という順で実行されます。
while文とfor文は機能面ではほとんど差がありませんが、次の「N回の繰り返し処理」等、for文で簡潔に書ける処理はfor文で書くのが一般的です。
N回の繰り返し処理
for文を使うとき、ほとんどは「N回の繰り返し処理」のパターンです。
動作の細かい部分がわからない人は、とりあえずこのパターンを覚えるところから始めましょう。
for (int i = 0; i < N; i++) { 処理 }
for文を使うときのコツ
「N回の繰り返し処理」のfor文を使うときは、「初期化」「条件式」「更新」の細かい動作を考えないようにしましょう。
よりおおざっぱに、for文はiが1ずつ増えながらN回処理を繰り返す機能と考えた方が、for文を使うプログラムを書きやすくなります。
また、ループでどう書けばよいかわからなくなったときは、まずループを使わずにプログラムを書いてみて、その後ループで書き直すという方法が有効です。
以下の2つのプログラムはその例です。これに関しては2.01.ループの書き方でより詳しく説明します。
ループを使わないプログラム
cout << "hello for :" << 0 << endl; cout << "hello for :" << 1 << endl; cout << "hello for :" << 2 << endl;
ループで書き直したプログラム
for (int i = 0; i < 3; i++) { cout << "hello for :" << i << endl; }
breakとcontinue
while文とfor文を制御する命令として、breakとcontinueがあります。
break
breakはループを途中で抜けるための命令です。
breakを使ったプログラムの例です。
#include <bits/stdc++.h> using namespace std; int main() { // breakがなければこのループは i == 4 まで繰り返す for (int i = 0; i < 5; i++) { if (i == 3) { cout << "ぬける" << endl; break; // i == 3 の時点でループから抜ける } cout << i << endl; } cout << "終了" << endl; }
実行結果
0 1 2 ぬける 終了
if文で i == 3
が真になったとき、break;
の命令を実行することでforループを抜け、終了
と出力しています。
continue
continueは後の処理をとばして次のループへ行くための命令です。
continueを使ったプログラムの例です。
#include <bits/stdc++.h> using namespace std; int main() { for (int i = 0; i < 5; i++) { if (i == 3) { cout << "とばす" << endl; continue; // i == 3 のとき これより後の処理をとばす } cout << i << endl; } cout << "終了" << endl; }
実行結果
0 1 2 とばす 4 終了
上のプログラムでは、if文で i == 3
が真になったとき、continue;
の命令を実行することでcontinueより下の部分を飛ばし、次のループに入ります。
細かい話
細かい話なので、飛ばして問題を解いても良いです。
for文とwhile文の違い
for文とwhile文の違いは主に2点あります。「カウンタ変数のスコープ」と「continueをしたときの動作」です。
カウンタ変数のスコープ
for文のカウンタ変数はwhile文よりスコープが狭くなります。
次の例では、for文のカウンタ変数であるi
がスコープの範囲外で使われているため、コンパイルエラーが発生しています。
#include <bits/stdc++.h> using namespace std; int main() { int j = 0; // jのスコープはmain関数の終わりまで while (j < 3) { cout << "Hello while" << endl; j++; } for (int i = 0; i < 3; i++) { // iのスコープはforの終わりまで cout << "Hello for" << endl; } cout << j << endl; cout << i << endl; }
コンパイルエラー
In function ‘int main()’: 18:13: error: ‘i’ was not declared in this scope cout << i << endl; ^
「変数のスコープ」で見たエラーと同じく、‘i’ was not declared in this scope
('i'はこのスコープで宣言されていません)というエラーが出ています。
while文で使っている変数j
のスコープは6行目からmain関数の終わりまでですが、
for文の「初期化」の場所で宣言している変数i
のスコープは、for文の{ }
中(12行目から14行目)だけになります。
continueをしたときの動作
while文でcontinueをすると更新処理を飛ばしてしまう事があるので、注意が必要です。
例を見てみましょう。
#include <bits/stdc++.h> using namespace std; int main() { for (int i = 0; i < 5; i++) { if (i == 3) { cout << "forとばす" << endl; continue; } cout << "for" << i << endl; } cout << "for終了" << endl; int j = 0; while(j < 5) { if (j == 3) { cout << "whileとばす" << endl; continue; } cout << "while" << j << endl; j++; } cout << "while終了" << endl; }
実行結果
for0 for1 for2 forとばす for4 for終了 while0 while1 while2 whileとばす whileとばす whileとばす (無限に続く)
for文のcontinueは先に説明したとおりですが、while文では無限ループになってしまっています。
j == 3
のとき、12行目のcontinue;
より後を飛ばして次のループに行っていますが、よく見てみるとj++
の処理も飛ばされてしまっています。
そのため、変数j
の値は永遠に3
のままとなり、無限ループになってしまいます。
省略したfor文
for文の「初期化」「条件式」「更新」の部分は、必要が無い場合省略できます。
次のように書いた場合、for文の動作はwhile文と完全に同じものになります。
int i = 0; for (; i < n;) { i++; }
「条件式」の部分を省略した場合、true
と書いたときと同じ動作になります。
次のプログラムは無限ループになります。
for (int i = 0; ; i++) { cout << i << endl; }
{ }
の省略
if文と同様に、for文やwhile文の処理が一文のみの場合も{ }
を省略できます。
#include <bits/stdc++.h> using namespace std; int main() { for (int i = 0; i < 3; i++) cout << "Hello!" << endl; }
for文のネスト
if文と同様、for文とwhile文もネストさせることができます。そのような書き方は多重ループと呼ばれます。
詳しくは2.02.多重ループで説明します。
#include <bits/stdc++.h> using namespace std; int main() { for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { cout << "i: " << i << ", j:" << j << endl; } } }
実行結果
i:0, j:0 i:0, j:1 i:1, j:0 i:1, j:1
問題
リンク先の問題を解いてください。
ABCの問題
ここまでの知識だけで解ける問題をAtCoder Beginner Contestから再び紹介します。練習問題だけでは物足りない人は解いてみてください。
「易しめ」と書いてあるものも今までのABCの問題よりも難易度が高いことに注意してください。
解けない場合、2.01.ループの書き方や2.02.多重ループを読んでから再挑戦してみてください。
易しめ
- B - Hina Arare
- B - Theater
- B - Harshad Number
- B - Addition and Multiplication
- B - Collecting Balls (Easy Version)