forループ

forループは、 whileループと同じ目的で使用される。forを使用すると、ループの反復に関する定義や式を同じ行に記述することができる。

forは、実際にはforeachほどは使用されないが、まずforループを理解しておくことが重要だ。foreachについては、後の章で説明する。

whileループのセクション

whileループは、ループ条件を評価し、その条件がtrueである限り、ループの実行を続ける。例えば、1から10までの数字を出力するループでは、11 未満という条件をチェックする。

while (number < 11)
D

ループを反復するには、ループの最後にnumberを加算する:

++number;
D

Dコードとしてコンパイル可能にするには、numberは最初の使用前に定義されている必要がある:

int number = 1;
D

最後に、ループ本体内の実際の処理がある:

writeln(number);
D

これらの4つのセクションは、次のように希望するループに結合できる:

int number = 1;         // ← 準備

while (number < 11) {   // ← 条件チェック
    writeln(number);    // ← 実際の作業
    ++number;           // ← 反復
}
D

whileループの反復中に、whileループのセクションは次の順序で実行される:

準備

条件確認
実際の作業
反復

条件確認
実際の作業
反復

...

break文またはスローされた例外も、ループを終了させることができる。

forループのセクション

forループは、これらのセクションの3つを1行にまとめる。これらは、forループの括弧内にセミコロンで区切って記述される。ループ本体には実際の処理のみが含まれる:

for (/* 準備 */; /* 条件チェック */; /* 反復 */) {
    /* 実際の作業 */
}
D

同じコードをforループとして記述した例である:

for (int number = 1; number < 11; ++number) {
    writeln(number);
}
D

forループの利点は、ループ本体に多数の文がある場合にさらに明らかになる。ループ変数を加算する式は、ループの他の文と混在することなく、for行で表示される。また、宣言された変数がループの一部としてのみ使用され、周囲の他のコードでは使用されていないこともより明確になる。

forループのセクションは、whileループと同じ順序で実行される。breakおよびcontinue文も、forループとまったく同じように機能する。whileループとforループの唯一の違いは、ループ変数の名前スコープだ。これについては、以下で説明する。

非常に一般的だが、反復変数は整数である必要はなく、また、加算によってのみ変更される必要もない。例えば、次のループは、前の浮動小数点値の半分を出力するために使用される。

for (double value = 1; value > 0.001; value /= 2) {
    writeln(value);
}
D

中括弧で囲んで定義することで、複数のループ変数を定義することができる。例えば、次のループは、異なる型の2つの変数を定義している。

for ({ int i = 0; double d = 0.5; } i < 10; ++i) {
    writeln("i: ", i, ", d: ", d);
    d /= 2;
}
D

準備セクションは、強調表示された中括弧で囲まれた部分であり、準備セクションと条件セクションの間にはセミコロンがないことに注意。

セクションは空にすることもできる

forループの3つのセクションはすべて空にすることができる:

すべてのセクションが空の場合、forループは無限ループを意味する:

for ( ; ; ) {
    // ...
}
D

このようなループは、決して終了しない、あるいはbreak文で終了するように設計することができる。

ループ変数の名前スコープ

forループとwhileループの唯一の違いは、ループの準備時に定義される変数の名前スコープだ:変数は、forループ内でのみアクセス可能で、ループ外からはアクセスできない:

for (int i = 0; i < 5; ++i) {
    // ...
}

writeln(i);   // ← コンパイルエラー
              //   iはここでアクセスできない
D

一方、whileループを使用する場合、変数はループを含む同じ名前スコープで定義されるため、ループ終了後も名前はアクセス可能だ:

int i = 0;

while (i < 5) {
    // ...
    ++i;
}

writeln(i);   // ← ここで'i'にアクセスできる
D

前の章で、名前は最初に使用される場所にできるだけ近い場所で定義するというガイドラインを紹介した。このガイドラインの根拠と同様に、変数の名前空間は小さいほど良い。この点から、ループ変数がループの外で必要ない場合は、whileループよりもforループの方が良い。

演習
  1. 次の9x9の表を、2つのforループ(1つは他方の内部にネスト)を使用して出力しよう:
    0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 
    1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 
    2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 
    3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 
    4,0 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 
    5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 
    6,0 6,1 6,2 6,3 6,4 6,5 6,6 6,7 6,8 
    7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 
    8,0 8,1 8,2 8,3 8,4 8,5 8,6 8,7 8,8 
  2. 1つまたは複数のforループを使用して、幾何学的なパターンを生成するために必要な数の*文字を出力しよう:
    *
    **
    ***
    ****
    *****
    
    ********
     ********
      ********
       ********
        ********
    
    など。