二重ループ(九九)
ループの中にループを置く
成績表を紙に書くところを想像してください。1 人目の行を左から右へ埋めて、改行して 2 人目の行へ移り、また左から右へ埋めます。この「行を進む動き」と「列を進む動き」は別ものなので、ループも 2 つ要ります。外側が行、内側が列です。
ループの中にループを書くことを 入れ子 といいます。書き方は特別ではなく、for の中身にもう 1 つ for を置くだけです。
for (i = 1; i <= 3; i++) {
for (j = 1; j <= 4; j++) {
printf("%d-%d ", i, j);
}
printf("\n");
}内側は毎回ゼロから回り直す
動きを追ってみます。外側の i が 1 になると、内側の j が 1 から 4 まで回りきります。内側が終わって初めて外側の i が 2 に進み、そこで内側の j は また 1 から 回り始めます。
つまり内側の中身は、外側 3 回 × 内側 4 回で合計 12 回動きます。回数がかけ算になるのが入れ子の性質で、外側と内側をそれぞれ 100 回にすると 1 万回になります。手軽に重い処理が書けてしまうので、回数の見積もりは意識してください。
改行の printf("\n") を置く場所も重要です。内側のループの 外 に置くと 1 行ぶんの区切りになり、内側の中に置くと数字が 1 個ずつ縦に並んでしまいます。表を作るときはここが一番の間違いどころです。
ループ変数を使い分ける
外側と内側で同じ変数名を使い回すと、内側が外側のカウンタを壊してしまい、ループが終わらなくなります。外側は i、内側は j と分けるのが C の慣習です。3 重になったら k を使います。
桁をそろえる
表として読ませたいときは、数字の幅をそろえます。第2章で学んだ書式指定に幅を足して %3d と書くと、3 桁ぶんの場所を取り、足りない分は左側が空白で埋まります。1 桁の 1 と 2 桁の 81 が同じ幅になるので、縦の線がきれいにそろいます。
幅を指定しない %d だと、数字の桁数がそのまま列のずれになります。九九なら 1 桁と 2 桁が混ざるので、右へ行くほど列が波打ちます。区切りに空白を 1 つ入れて "%d " と書く手もありますが、これでは桁の違いを吸収できません。成績表のように数字を縦に読ませたい出力では、幅の指定はほとんど必須だと考えてください。
内側の回数を外側で変える
内側のループの条件に、外側の変数を書くこともできます。たとえば for (j = 1; j <= i; j++) とすると、1 段目は 1 個、2 段目は 2 個、と行ごとに個数が変わり、三角形の形になります。九九の表で同じ計算が 2 度出てくる部分を省いた、いわゆる半分の表もこの書き方で作れます。内側の回数は外側ごとに決め直されている、と理解していれば自然に書けます。
では、入れ子の定番である九九の表を作ってみましょう。行が段、列がかける数です。
要件
- 1行目に 九九の表 と表示する
- 外側のループで段、内側のループでかける数を回す
- かけ算の結果は printf("%3d", i * j) の形で表示する
- 1つの段を出し終えたら改行する
入出力例
main("") → "九九の表
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81"