アナログ時計を見てください。長針が1周する間に、短針は1目盛りだけ進みます。外側が1回進む間に、内側は最初から最後まで回りきる。これがループのネスト(入れ子)です。
外側3回、内側3回なら、本体が実行されるのは 3×3 = 9回。掛け算になるのがポイントです。
定番中の定番、九九表を作りましょう。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 9; i++) { // 段
for (int j = 1; j <= 9; j++) { // 掛ける数
printf("%3d", i * j);
}
printf("\n"); // 1段ぶん終わったので改行
}
return 0;
}9行9列の表が出ます。%3d は「3桁ぶんの幅で右寄せ」というprintfの書式指定で、これがあるおかげで桁が揃います。
このコードで本当に大事なのは、改行の位置です。printf("\n") は内側のループの外、外側のループの中にあります。ここを間違えると形が崩れます。
改行を内側のループの中に入れると、数字が1つ出るたびに改行されて縦1列になります。改行を外側のループの外に出すと、81個の数字が全部1行に並びます。「内側が回りきったら、1行ぶん終わり」——この対応を意識すると、表の出力で迷わなくなります。
内側の条件に外側の変数を使うと、段ごとに長さを変えられます。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= i; j++) { // 上限が外側の i
printf("*");
}
printf("\n");
}
return 0;
}* が1個、2個、3個…と増えて三角形になります。ネストの本当の威力はここで、内側と外側を連動させると一気に表現力が上がります。
前のトピックで触れた「breakは内側しか抜けない」問題も片付けておきましょう。外側まで抜けたいときはboolのフラグを使います。
#include <stdio.h>
int main(void) {
bool found = false;
for (int i = 1; i <= 3 && !found; i++) { // フラグを外側の条件にも入れる
for (int j = 1; j <= 3; j++) {
if (i * j == 4) {
printf("見つけた: %d x %d\n", i, j);
found = true;
break; // 内側を抜ける
}
}
}
return 0;
}内側で found = true にしてから break すると、外側の継続条件 !found が偽になって外側も終わります。少し回りくどく見えますが、流れが1本道なので後から読む人に優しい書き方です。
罠を2つ。
その1、カウンタ名の使い回し。 外側も内側も i にすると、内側が外側のカウンタを壊して動きがめちゃくちゃになります。i, j, k と分けてください。
その2、実行回数は掛け算。 外側 n 回・内側 n 回なら本体は n×n 回です。n が 1000 なら100万回。ネストは静かに重くなります。三重にすれば n×n×n。「入れ子を1つ増やすと桁が変わる」という感覚は、今のうちに持っておいて損はありません。
まとめます。外側1周につき内側は回りきる。表の形を決めるのは改行の位置。カウンタ名は分ける。実行回数は掛け算で効いてくる。