C言語を習得する上で、避けて通れない非常に重要なテーマが「繰り返し処理(ループ)」です。
コンピュータが得意とする「高速かつ正確な単純作業」を最大限に引き出すためには、この繰り返し処理を自在に操るスキルが欠かせません。
プログラミングの基礎である制御構造には「順次」「分岐」「反復」の3つがありますが、本記事ではその中心となる反復(繰り返し)処理に焦点を当て、基礎から応用までを徹底的に解説します。
C言語における繰り返し処理の役割と重要性
プログラムを書く際、同じような処理を何度も繰り返す場面が頻繁に登場します。
例えば、1から100までの数字を表示したり、膨大なデータの中から特定の情報を探し出したりする場合、それらをすべて1行ずつ記述するのは非効率的です。
繰り返し処理を使用することで、数行のコードで数万回の処理を実行できるようになり、ソースコードの可読性とメンテナンス性が劇的に向上します。
C言語には主に3種類の繰り返し文が用意されており、用途に応じてこれらを使い分けることが効率的なプログラミングの第一歩となります。
for文による反復処理の基礎
for文は、あらかじめ繰り返す回数が決まっている場合に最も適した構文です。
カウンタ変数の初期化から条件判定、変数の更新までを1行にまとめて記述できるため、構造が非常に分かりやすいのが特徴です。
for文の基本構文と実行順序
for文の基本的な書き方は以下の通りです。
for (初期化式; 条件式; 更新式) {
// 繰り返したい処理
}
この構文は、以下の手順で実行されます。
- 初期化式が最初に1回だけ実行されます。通常はカウンタ変数の宣言と初期値の代入を行います。
- 条件式が評価されます。結果が「真(0以外)」であれば、ブロック内の処理が実行されます。
- ブロック内の処理が終了すると、更新式が実行されます。
- 再び「条件式」の判定に戻ります。条件が「偽(0)」になるまで、2〜4が繰り返されます。
実践的なコード例
以下は、0から4までの数値を表示する簡単なプログラムです。
#include <stdio.h>
int main(void) {
for (int i = 0; i < 5; i++) {
printf("現在の値は %d です\n", i);
}
return 0;
}
この例では、int i = 0 で変数を初期化し、i < 5 が満たされている間、処理を繰り返します。
各ループの最後に i++(インクリメント)によって i の値が1ずつ増えていきます。
for文の高度な使い方
for文の各要素は、必要に応じて省略したり、複数の式を記述したりすることも可能です。
複数の変数を制御する
カンマ演算子を使用することで、複数のカウンタ変数を同時に扱うことができます。
for (int i = 0, j = 10; i < j; i++, j--) {
printf("i = %d, j = %d\n", i, j);
}
無限ループの作成
すべての式を省略すると、終了条件のない無限ループになります。
for (;;) {
// 永久に繰り返される処理
}
ただし、無限ループを作成する場合は、後述する break 文などを用いて適切に脱出する仕組みを設けないと、プログラムがフリーズしたような状態になるため注意が必要です。
while文による条件付き反復
while文は、「ある条件が満たされている間はずっと繰り返す」という処理に適しています。
繰り返す回数が事前に決まっていない場合や、外部の状態(フラグや入力値)によって終了を判断する場合に多用されます。
while文の基本構文
while (条件式) {
// 繰り返したい処理
}
while文は、まず最初に「条件式」を評価します。
条件が真であればブロック内を実行し、偽であれば一度も実行せずにループを終了します。
実践的なコード例
ユーザーが 0 を入力するまで数値を加算し続けるプログラムを考えてみましょう。
#include <stdio.h>
int main(void) {
int num = -1;
int sum = 0;
while (num != 0) {
printf("数値を入力してください(0で終了): ");
scanf("%d", &num);
sum += num;
}
printf("合計値は %d です\n", sum);
return 0;
}
このように、ループの回数がユーザーの操作に依存する場合、while文を使用するのが最適です。
while文での無限ループと注意点
while文で最も多いミスは、ループの中で条件式の結果を変える処理を忘れてしまうことです。
これを怠ると、条件が永久に真のままとなり、プログラムが停止しなくなります。
意図的に無限ループを作る場合は、条件式に 1(真を意味する定数)を記述するのが一般的です。
while (1) {
// 処理
if (条件) break; // 特定の条件で脱出
}
do-while文:最低1回の実行を保証する
do-while文は、while文のバリエーションの一つですが、「条件判定を処理の後に行う」という大きな違いがあります。
do-while文の基本構文
do {
// 繰り返したい処理
} while (条件式);
末尾にセミコロン(;)が必要な点に注意してください。
この構文では、まずブロック内の処理が実行され、その後に条件判定が行われます。
そのため、条件に関わらず最低でも1回は必ず処理が実行されることが保証されます。
活用シーン:メニュー選択
ユーザーにメニューを選択させ、無効な入力があった場合に再入力を促すような処理に非常に適しています。
#include <stdio.h>
int main(void) {
int choice;
do {
printf("1. 開始\n2. 設定\n3. 終了\n選択してください: ");
scanf("%d", &choice);
} while (choice < 1 || choice > 3);
printf("%d 番が選択されました\n", choice);
return 0;
}
この例では、最初に必ずメニューが表示され、適切な値が入力されるまで繰り返しを継続します。
for文とwhile文の使い分けガイド
どちらの構文を使っても同じ処理を書くことは可能ですが、プログラムの可読性を高めるためには明確な使い分けが必要です。
使い分けの基準表
| 構文 | 適したケース | 特徴 |
|---|---|---|
for | 回数が決まっている、配列の走査 | 初期化・条件・更新が1か所にまとまる |
while | 条件によって終了が決まる | ループ変数が不要な場合も使いやすい |
do-while | 最低1回は実行したい | 入力チェックやメニュー表示に最適 |
判断に迷ったときのアドバイス:
「カウンタ変数(iなど)」を使って「n回繰り返す」ことが目的であれば、迷わず for 文を選択してください。
一方で、ファイルが終わるまで読み込む、特定のフラグが立つまで待機するといった「状態」に依存する場合は while 文が自然です。
ループを制御する:breakとcontinue
繰り返し処理の途中で、流れを強制的に変えたい場合があります。
その際に使用するのが break 文と continue 文です。
break文:ループの強制終了
break 文が実行されると、現在実行中のループ処理を直ちに中断し、ループの次の行へジャンプします。
for (int i = 1; i <= 10; i++) {
if (i == 6) break; // 6になったらループを抜ける
printf("%d ", i);
}
// 出力結果: 1 2 3 4 5
continue文:次の回へスキップ
continue 文が実行されると、その回の残りの処理をスキップし、次の繰り返しの判定(または更新式)へ移動します。
ループ自体は終了しません。
for (int i = 1; i <= 5; i++) {
if (i == 3) continue; // 3の時だけ表示をスキップ
printf("%d ", i);
}
// 出力結果: 1 2 4 5
特定の条件のときだけ処理を除外したい(例えば、偶数だけ処理したい、エラーデータだけ飛ばしたいなど)場合に非常に便利です。
多重ループ(入れ子構造)の理解
ループの中にさらにループを入れる構造を「多重ループ」または「ネスト」と呼びます。
2次元的なデータ構造を扱う際に必須のテクニックです。
2重ループの基本(九九の表)
九九の表を作成するプログラムは、多重ループの典型的な例です。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 9; i++) { // 外側のループ(行)
for (int j = 1; j <= 9; j++) { // 内側のループ(列)
printf("%2d ", i * j);
}
printf("\n"); // 1行終わるごとに改行
}
return 0;
}
外側のループが1回回るごとに、内側のループが指定回数(この場合は9回)すべて実行されます。
多重ループを使用する際は、階層が深くなりすぎるとコードの可読性が著しく低下し、動作も重くなる(計算量が増える)ため、注意が必要です。
繰り返し処理での注意点とバグ対策
繰り返し処理は強力ですが、一歩間違えると重大なバグ(不具合)の原因になります。
開発時に特に意識すべきポイントを整理します。
1. 無限ループの回避
意図しない無限ループは、CPUのリソースを過剰に消費し、システム全体のパフォーマンスを低下させます。
- 条件式がいつか必ず「偽」になるかを確認する。
while文内でカウンタ変数を更新し忘れていないかチェックする。- 浮動小数点数(
floatなど)を条件式の比較に使うのを避ける(誤差により正確な一致が判定できない場合があるため)。
2. オフバイワンエラー(境界値のミス)
「10回繰り返したいのに、9回しか実行されない」あるいは「11回実行されて配列の範囲外にアクセスしてしまう」というミスは非常に多いです。
i < 10なのかi <= 10なのか。- 初期値は
0なのか1なのか。
これらの組み合わせを慎重に設計してください。C言語の配列は0から始まるため、「0から始めて、要素数未満まで繰り返す」(例:for (int i = 0; i < N; i++))というパターンを基本形として覚えるのが安全です。
3. 変数のスコープ
C99規格以降、for 文の初期化式内で宣言された変数は、そのループ内でのみ有効となります(ブロックスコープ)。
for (int i = 0; i < 5; i++) {
// ここでは i を使える
}
// ここでは i は消滅しているためエラーになる
ループの外でもその値を使い回したい場合は、for 文の前で変数を宣言しておく必要があります。
実践:繰り返し処理を使ったアルゴリズム
学んだ知識を定着させるために、具体的な応用例を見てみましょう。
配列内の最大値を見つける
配列の全要素を1つずつチェックする「線形探索」は、繰り返し処理の基本です。
#include <stdio.h>
int main(void) {
int scores[] = {65, 92, 48, 77, 85};
int n = sizeof(scores) / sizeof(scores[0]); // 要素数の計算
int max = scores[0]; // 暫定の最大値
for (int i = 1; i < n; i++) {
if (scores[i] > max) {
max = scores[i]; // より大きな値が見つかったら更新
}
}
printf("最高得点は %d 点です\n", max);
return 0;
}
合計値と平均値の算出
統計処理も繰り返しの得意分野です。
#include <stdio.h>
int main(void) {
int data[] = {10, 20, 30, 40, 50};
int count = sizeof(data) / sizeof(data[0]);
double sum = 0;
for (int i = 0; i < count; i++) {
sum += data[i];
}
printf("合計: %.1f, 平均: %.1f\n", sum, sum / count);
return 0;
}
このように、「データの集合に対して同じ操作を適用する」という考え方が、実務におけるプログラミングの根幹となります。
C言語の繰り返し処理を学ぶためのリソース
C言語の学習をさらに深めたい方には、以下の外部リソースも役立ちます。
- cppreference.com (C language) – C言語の仕様に関する詳細なリファレンスサイトです。
- Microsoft Learn – C言語のドキュメント – Visual C++ を中心とした実践的な解説が豊富です。
繰り返し処理の概念は、JavaやPython、JavaScriptといった他の言語にもほぼ共通して存在します。
ここでC言語の厳密な構文でループをマスターしておくことは、将来他の言語を学ぶ際にも大きなアドバンテージとなるでしょう。
まとめ
C言語における繰り返し処理は、効率的なプログラムを書くための最重要パーツです。
- for文:回数指定のループに最適。
- while文:条件重視のループに最適。
- do-while文:最低1回の実行が必要な場合に活用。
- break/continue:ループの流れを細かく制御。
- 多重ループ:複雑なデータ構造の操作に不可欠。
これらの道具を正しく使い分けることで、冗長なコードを排除し、美しく動作するプログラムを構築できるようになります。
特に「境界値の条件」や「無限ループ」といった注意点に気を配りながら、実際に多くのコードを書いて、その挙動を体感してみてください。
繰り返し処理を完全にマスターすれば、あなたのC言語プログラミングスキルは一段上のレベルへと到達するはずです。






