繰り返し (for)

復習

自動インクリメント/デクリメント演算子

意味
a += b a = a + b
a -= b a = a - b
a++ a = a + 1
a-- a = a - 1

条件式

条件式 意味
a == b aとbが等しければtrue、そうでなければfalse
a != b aとbが等しくなければtrue、そうでなければfalse
a >= b aがbより大きいか等しければtrue、そうでなければfalse
a <= b aがbより小さいか等しければtrue、そうでなければfalse
a > b aがbより大きいければtrue、そうでなければfalse
a < b aがbより小さければtrue、そうでなければfalse

for 文を用いた繰り返し実行

今までのプログラムは、書いてある命令文を最大でも1回実行するだけであった。

以降では、プログラムの中にある命令文を繰り返し実行するような機構を紹介する。

繰り返し実行を行う際に最もよく使用される文は、for文 と呼ばれるものである。

for (int i = 0; i < 10; i++)
  System.out.println("iの値は" + i);

これを日本語で表現すると、以下のように表せる。

変数 i の値が 0 から      → int i = 0
10 未満の間は、           → i < 10
i の値を1づつ加算しながら → i++
以下の命令文を実行する。
「System.out.println("iの値は" + i);」

つまり、上記の繰り返しを実行すると、以下のように表示される。

iの値は0
iの値は1
iの値は2
iの値は3
iの値は4
iの値は5
iの値は6
iの値は7
iの値は8
iの値は9

for 文の構造

for 文は以下のような構造をしている。

for (<初期化式> ; <条件式> ; <ステップを進める式>)
  文

<初期化式> ; <条件式> ; <ステップを進める式> とあるが、 それぞれをセミコロン「;」で区切りながら記述する。

<初期化式>

for (<初期化式> ; <条件式> ; <ステップを進める式>)
  文

for 文を開始する際に1度だけ実行される。通常はここでループに使用する変数を宣言して、その変数を初期化する

for (int i = 0; i < 10; i++)
  System.out.println("iの値は" + i);

上記の例では、int型の変数 i を宣言し、0を代入している。

ここで注意すべきことは、この変数 i は forにぶら下がっている文の中でしか使用できない。つまり、次のようなプログラムはエラーになる。

for (int i = 0; i < 10; i++)
  System.out.println("iの値は" + i);

// エラー。ここで変数 i は使用できない。
System.out.println("for文が終わったあとのiの値は" + i);

ここで、変数iの値を参照したい場合、iをfor文の外で宣言する必要がある。

int i;
for (i = 0; i < 10; i++)
  System.out.println("iの値は" + i);

System.out.println("for文が終わったあとのiの値は" + i);

ただし、外側で使用する機会がないのであれば、for文の<初期化式>内で宣言することが望ましい。

ここで宣言する変数の名前や、初期化する際の値は何でもよい。慣例では i, j, k といった名前をつけることが多い。

ループに使用する変数を「ループ制御変数」と呼ぶこともあるが、通常の変数と扱いは変わらない。

条件式

for (<初期化式> ; <条件式> ; <ステップを進める式>)
  文

for文の中で、毎回の繰り返しの最初に条件の比較が行われる。この条件の比較結果がtrueになった場合、繰り返しが実行される。言い換えると、この条件の比較結果がtrueであるうちは、毎回命令文を実行する

for (int i = 0; i < 10; i++)
  System.out.println("iの値は" + i);

上記の例では、i の値が 10 未満である限り「System.out.println("iの値は" + i);」を実行する。

ここで注意すべきことは、この条件比較は毎回行われるため、以下のようなプログラムでは何も表示されない。

for (int i = 10; i < 10; i++)
  System.out.println("iの値は" + i);

i の値が 10 から繰り返しを開始しようとしているが、 i < 10 を満たさないために、forにぶら下がっている文を一度も実行しない。

ステップを進める式

for (<初期化式> ; <条件式> ; <ステップを進める式>)
  文

for文にぶら下がっている文を実行し終わった後、つまり、毎回の繰り返しの最後に実行される。通常はここでループに使用する変数を操作する。この操作が終了したら、ループの1周分が終了し、「<条件>の比較」へ戻る。

ここで、ループ制御変数の値を操作することによって、ループの次の周を実行させるかfor文を終了させるか選べる。

for (int i = 0; i < 10; i++)
  System.out.println("iの値は" + i);

上記の例では、「System.out.println("iの値は" + i);」を実行した後に、i++ が実行される。ループの先頭ではなくループの最後に実行されるため、最初に「System.out.println("iの値は" + i);」で表示される結果は「iの値は0」である。

iの値は0
iの値は1
iの値は2
iの値は3
iの値は4
iの値は5
iの値は6
iの値は7
iの値は8
iの値は9

と、次々と表示して行くと、「iの値は9」と表示された瞬間のループ制御変数 i の中身は 9 になっている。この後、i++ によってiの値が10になり、i < 10 を満たさなくなるため、ループは終了する。

ループの条件を i <= 10 とした場合を考えてみる。

for (int i = 0; i <= 10; i++)
  System.out.println("iの値は" + i);

このループを実行することによって、以下のように表示されるはずである。

iの値は0
iの値は1
iの値は2
iの値は3
iの値は4
iの値は5
iの値は6
iの値は7
iの値は8
iの値は9
iの値は10

また、<ステップを進める式>部分を i++ から i += 2 に変更した場合を考えてみる。

for (int i = 0; i < 10; i += 2)
  System.out.println("iの値は" + i);

これによって、繰り返しの1ステップが終わるごとに、iの値は2づつ増える。

このループを実行することによって、以下のように表示されるはずである。

iの値は0
iの値は2
iの値は4
iの値は6
iの値は8

for (<初期化式> ; <条件式> ; <ステップを進める式>)
  文

実際に繰り返す文を記述する。ここに命令文を2個以上書きたい場合は、ブロック { } で括ってやればよい。

for (<初期化式> ; <条件式> ; <ステップを進める式>) {
  命令文
  命令文
  ...
  命令文
}

for 文の流れ

for (<初期化式> ; <条件式> ; <ステップを進める式>)
  文
  1. <初期化式> を実行する
  2. <条件式> を比較する
  3. 文を実行する
  4. <ステップを進める式> を実行する
  5. 2 へ

よく使われるパターン

for (int i = (n); i < (m); i++) {
  (命令文の列)
}

i を n から始めて、m - 1 まで順に命令文の列を実行していく。

つまり、 i = {n, n+1, ... , m-1} といった範囲で実行され、繰り返し回数は m - n 回になる。

その中でも良く使われるのが、i の初期値が 0 の繰り返しである。

for (int i = 0; i < 10; i++) {
  (命令文の列)
}

i = {0, 1, ..., 9} の範囲で、つまり、10回だけ命令文の列を実行する。

10のように定数を入れて、定数回だけ繰り返す方法もあるが、以下のようにコンソールから入力された値だけ、命令文の列の実行を繰り返すというプログラムも書ける。

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int input = Integer.parseInt(reader.readLine());

for (int i = 0; i < input; i++) {
  (命令文の列)
}

この他にも、以下のような繰り返し文が良く使用される。

for (int i = 1; i <= (n); i++) {
  (命令文の列)
}

上記の例では、 i = {1, 2, ..., n} となる。こちらも n 回だけ繰り返される。

他にも、iの値をカウントダウンしながらループする方法もある。

for (int i = (n); i >= (m); i--) {
  (命令文の列)
}

上記の場合は、n - m + 1 回だけ実行されることに注意すること。

for文の中で計算する

for文を用いた繰り返しの中で何らかの計算を行い、繰り返しの外でその計算結果を利用するという場面がよくある。

この場合、繰り返しに使うループ制御変数のほかに、毎回の繰り返しの計算を保存しておく変数が必要になる。この変数は、ループの外側で宣言する必要がある。

int total = 0;
for (int i = 1; i <= n; i++) {
  total += i;
}

上記の例は、1からnまでの総和を計算するプログラムので一部である。totalの値は和の演算の単位元で初期化している。

また、以下のようなプログラムを書けば、10回の入力の総和を計算することができる。

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int total = 0;
for (int i = 1; i <= 10; i++) {
  System.out.print(i + "回目の入力");
  int input = Intger.parseInt(reader.readLine());
  total += input;
}
System.out.println("入力の合計は" + total);

二重ループ

繰り返しの中で、さらに繰り返しを行うこともできる。

for (int i = 0; i < n; i++) {
  for (int j = 0; j < m; j++) {
    // ...
  }
}

上記の例では、最内の繰り返し部分を n * m 回繰り返す。外側のループと内側のループで、ループ制御変数が異なる (i, j) 点に注意すること。