
C言語の基本|多重ループの使い方
外側で行を進め、内側で列を埋める。多重ループで、表や座標のような2次元の処理をすっきり作ろう。
1つのループで表現できるのは、基本的に一方向の繰り返しです。しかし、プログラムでは、行と列のように2つの方向を組み合わせて処理したい場面があります。
たとえば、次のような処理です。
- 同じ並びを複数行表示する
- 建物の各階にある設備を順番に確認する
- 行と列で構成された表を作る
- 記号を並べて図形を描く
- マス目の座標を順番に表示する
このような処理で役立つのが多重ループです。
多重ループは、あるループの中に別のループを入れる書き方です。特に、ループが外側と内側の2段になっているものを二重ループと呼びます。
二重ループでは、外側と内側に次のような役割を持たせるのが基本です。
- 外側のループは縦方向となる行を担当する
- 内側のループは横方向となる列を担当する
- 内側のループが終わったら、外側のループを次へ進める
この役割分担を理解すると、表やマス目を作る処理を読みやすく記述できます。
図1:外側の1回で内側が最後まで繰り返す流れ

この図から分かること
外側のループが1階を担当している間に、内側のループは区域1から区域4までをすべて処理します。
内側のループが終了すると、外側のループが2階へ進みます。その時点で内側のループは再び区域1から始まります。
外側が1回進むごとに、内側が最初から最後まで繰り返されることが二重ループの重要な特徴です。
多重ループと二重ループの違い
多重ループは、ループを入れ子にした構造全体を表す言葉です。
| 呼び方 | ループの段数 | 処理のイメージ |
|---|---|---|
| 単一ループ | 1段 | 一方向の繰り返し |
| 二重ループ | 2段 | 行と列を使った繰り返し |
| 三重ループ | 3段 | 層、行、列を使った繰り返し |
| 多重ループ | 2段以上の総称 | 入れ子になったループ全体 |
最初に理解したいのは二重ループです。
二重ループの動きが分かれば、三重ループでも考え方は変わりません。ただし、段数が増えるほど変数の組み合わせや実行回数が増えるため、処理を追いにくくなります。
for文を使った二重ループの基本形
for文の中に、もう1つのfor文を書くと二重ループになります。
for (外側の初期設定; 外側の継続条件; 外側の再設定) {
for (内側の初期設定; 内側の継続条件; 内側の再設定) {
繰り返す処理;
}
}行と列として書き換えると、次のようになります。
for (行の初期設定; 行の継続条件; 行の再設定) {
for (列の初期設定; 列の継続条件; 列の再設定) {
1マス分の処理;
}
}| ループ | 主な役割 | 典型的な処理 |
|---|---|---|
| 外側のループ | 行を進める | 1行目から4行目まで |
| 内側のループ | 列を進める | 1列目から4列目まで |
| 内側の処理 | 1つ分を表示する | 数値や座標を表示する |
| 内側の終了後 | 1行を終える | 改行する |
二重ループの実行順序
次の二重ループを考えてみましょう。
for (int row = 1; row <= 4; row++) {
for (int col = 1; col <= 4; col++) {
処理;
}
}実行されるrowとcolの組み合わせは、次のようになります。
| 外側のrow | 内側のcolの変化 |
|---|---|
| 1 | 1 → 2 → 3 → 4 |
| 2 | 1 → 2 → 3 → 4 |
| 3 | 1 → 2 → 3 → 4 |
| 4 | 1 → 2 → 3 → 4 |
処理順を並べると、次のとおりです。
- rowを1にする
- colを1にする
- colが4以下の間、内側の処理を繰り返す
- colが5になると内側のループを終了する
- rowを2にする
- 内側のcolを再び1にする
- 同じようにcolが4になるまで処理する
- rowが5になるまで繰り返す
外側が4回、内側も4回なので、最も内側の処理は合計16回実行されます。
外側の回数 × 内側の回数
4 × 4 = 16回多重ループを使わずに同じ行を表示する
最初に、多重ループを使わず、同じ数字の並びを4行表示してみましょう。
それぞれの行で、区域番号1から4までを表示します。
同じ区域番号の並びを4回繰り返して書くプログラム
ファイル名:9_8_1.c
#include <stdio.h>
int main(void)
{
int zone;
for (zone = 1; zone <= 4; zone++) {
printf("Z%d ", zone);
}
printf("\n");
for (zone = 1; zone <= 4; zone++) {
printf("Z%d ", zone);
}
printf("\n");
for (zone = 1; zone <= 4; zone++) {
printf("Z%d ", zone);
}
printf("\n");
for (zone = 1; zone <= 4; zone++) {
printf("Z%d ", zone);
}
printf("\n");
return 0;
}実行結果の例
Z1 Z2 Z3 Z4
Z1 Z2 Z3 Z4
Z1 Z2 Z3 Z4
Z1 Z2 Z3 Z4プログラムの詳しい解説
各for文では、zoneを1から4まで増やしています。
for (zone = 1; zone <= 4; zone++)ループ本体では、現在の区域番号を表示します。
printf("Z%d ", zone);1つのfor文が終了すると、改行を表示します。
printf("\n");この書き方でも、目的どおりの結果を表示できます。しかし、同じfor文とprintfを4回書いているため、重複が多くなっています。
行数を6行へ増やす場合は、同じ処理をさらに2つ追加しなければなりません。1行あたりの区域数を変更するときは、4つのfor文をすべて修正する必要があります。
二重ループで重複を減らす
同じ処理を二重ループで書くと、行数と列数を別々のループで管理できます。
二重ループで4階4区域の一覧を表示するプログラム
ファイル名:9_8_2.c
#include <stdio.h>
int main(void)
{
int floor;
int zone;
for (floor = 1; floor <= 4; floor++) {
for (zone = 1; zone <= 4; zone++) {
printf("Z%d ", zone);
}
printf("\n");
}
return 0;
}実行結果の例
Z1 Z2 Z3 Z4
Z1 Z2 Z3 Z4
Z1 Z2 Z3 Z4
Z1 Z2 Z3 Z4プログラムの詳しい解説
外側のfor文では、建物の階を1から4まで進めます。
for (floor = 1; floor <= 4; floor++)外側のループ本体に、区域を処理する内側のfor文があります。
for (zone = 1; zone <= 4; zone++)floorが1の間、zoneは1から4まで変化します。そのため、最初の行にZ1からZ4までが表示されます。
内側のループが終わったら、次のprintfで改行します。
printf("\n");この改行は、内側のfor文の外、外側のfor文の中にあります。そのため、区域を4つ表示し終わるたびに1回だけ実行されます。
その後、外側のfloorが2へ増えます。内側のfor文は初期設定から始まるため、zoneは再び1になります。
| floor | zoneの変化 | 表示後の動作 |
|---|---|---|
| 1 | 1 → 2 → 3 → 4 | 改行する |
| 2 | 1 → 2 → 3 → 4 | 改行する |
| 3 | 1 → 2 → 3 → 4 | 改行する |
| 4 | 1 → 2 → 3 → 4 | 改行する |
改行を書く場所が重要
二重ループでは、改行を書く位置によって表示結果が変わります。
今回のプログラムでは、改行を内側のループの後に書いています。
for (floor = 1; floor <= 4; floor++) {
for (zone = 1; zone <= 4; zone++) {
printf("Z%d ", zone);
}
printf("\n");
}この配置では、1行分となる4区域を表示した後に改行します。
改行を内側のループへ入れると、区域を1つ表示するたびに改行されます。
for (zone = 1; zone <= 4; zone++) {
printf("Z%d\n", zone);
}これでは横方向に並ばず、すべて縦に表示されます。
内側のループで1行の中身を作り、内側のループが終了した後で改行するという考え方が大切です。
図2:二重ループが4行4列のマス目を埋める様子

この図から分かること
外側のfloorが現在の行を決め、内側のzoneがその行の左から右までを順番に処理します。
zoneが1から4まで進むと1行が完成します。そこで改行し、floorを次へ進めます。
4行と4列を組み合わせているため、最も内側にあるprintfは合計16回実行されます。
floorとzoneで役割を明確にする
二重ループでは、外側と内側で異なる変数を使います。
| 変数 | 担当する方向 | 変化するタイミング |
|---|---|---|
| floor | 縦方向・行 | 内側のループがすべて終わった後 |
| zone | 横方向・列 | 内側の処理を1回実行するたび |
| row | 一般的な行番号 | 外側のループで使うことが多い |
| col | 一般的な列番号 | 内側のループで使うことが多い |
iやjを使ってもプログラムは動きます。
for (i = 1; i <= 4; i++) {
for (j = 1; j <= 4; j++) {
/* 処理 */
}
}ただし、floorやzone、rowやcolのような名前を使うと、それぞれの変数が何を担当しているか理解しやすくなります。
行番号と列番号を組み合わせる
内側の処理では、外側と内側の両方の変数を使用できます。
次のプログラムでは、階番号と区域番号を組み合わせ、各防災区域の位置を表示します。
階番号と区域番号を組み合わせて防災区域を表示するプログラム
ファイル名:9_8_3.c
#include <stdio.h>
int main(void)
{
int floor;
int zone;
for (floor = 1; floor <= 4; floor++) {
for (zone = 1; zone <= 4; zone++) {
printf("[F%d-Z%d] ", floor, zone);
}
printf("\n");
}
return 0;
}実行結果の例
[F1-Z1] [F1-Z2] [F1-Z3] [F1-Z4]
[F2-Z1] [F2-Z2] [F2-Z3] [F2-Z4]
[F3-Z1] [F3-Z2] [F3-Z3] [F3-Z4]
[F4-Z1] [F4-Z2] [F4-Z3] [F4-Z4]プログラムの詳しい解説
外側のfloorは、現在処理している階を表します。内側のzoneは、その階にある区域を表します。
printf("[F%d-Z%d] ", floor, zone);floorが1の間、zoneが1から4まで変化するため、次の4つが表示されます。
[F1-Z1] [F1-Z2] [F1-Z3] [F1-Z4]内側のループが終わると改行し、floorが2になります。内側のzoneは再び1から始まるため、2階の区域が順番に表示されます。
このように、外側と内側の変数を組み合わせると、行と列で決まる各マスの位置を表現できます。
内側のループは毎回初期状態に戻る
for文では、内側のループへ入るたびに初期設定が実行されます。
for (zone = 1; zone <= 4; zone++)外側のfloorが次へ進むと、内側のzoneは再び1に設定されます。
内側の変数が前の行の続きから始まるわけではありません。この再初期化によって、すべての階で区域1から区域4までを処理できます。
while文でも二重ループを作れる
多重ループはfor文だけの機能ではありません。while文の中にwhile文を書くこともできます。
基本的な形は次のとおりです。
外側の変数を初期化;
while (外側の条件) {
内側の変数を初期化;
while (内側の条件) {
処理;
内側の変数を更新;
}
外側の変数を更新;
}while文で二重ループを作る場合は、内側の変数を初期化する場所が重要です。
内側の変数は、外側のループが1回進むたびに開始値へ戻す必要があります。そのため、内側の変数の初期化は外側のwhile文の中、内側のwhile文の直前に書きます。
図3:while文の二重ループで内側の変数を戻す位置

この図から分かること
while文の二重ループでは、内側の変数を自分で開始値へ戻す必要があります。
zoneを外側のループよりも前で1回だけ初期化すると、1行目の処理が終わった時点でzoneは終了値を超えています。そのまま2行目へ進んでも、内側の条件は最初から偽になり、区域を処理できません。
多重ループを書くときの確認ポイント
多重ループを作るときは、次の点を確認すると処理を追いやすくなります。
- 外側のループが何を担当するか
- 内側のループが何を担当するか
- 外側が1回進む間に内側が何回動くか
- 内側の変数が適切に初期化されるか
- 内側と外側の変数が正しく更新されるか
- 改行が内側のループの外にあるか
- 最も内側の処理が合計何回実行されるか
- ネストを深くしすぎていないか
多重ループは、外側と内側の役割をはっきり分けると理解しやすくなります。内側で1行分の内容を作り、外側で必要な行数を作るという考え方を使えば、表や座標のような2次元の処理を重複の少ないコードで表現できます。
