C言語を学習する上で、避けては通れない最重要項目の一つが「繰り返し処理」です。
コンピュータは同じ作業を高速に、かつ正確に繰り返すことを得意としており、その能力を最大限に引き出すための構文がfor文です。
C言語のfor文は、他のプログラミング言語のループ構造の基礎となっており、その仕組みを深く理解することは、効率的なアルゴリズムを構築する第一歩となります。
本記事では、基本の書き方から応用的なテクニック、そして陥りやすい罠までを徹底的に解説します。
for文とは?繰り返し処理の基本概念
C言語において、特定の処理を何度も実行したい場合に使用するのがループ(繰り返し)構文です。
その中でもfor文は、繰り返す回数があらかじめ決まっている場合や、一定のルールに従って変化する値を扱う場合に最適な設計になっています。
例えば、1から100までの数字を順番に表示する場合、printf関数を100回記述するのは非効率的です。
しかし、for文を利用すれば、わずか数行のコードで同じ動作を実現できます。
for文は、プログラムの記述量を減らすだけでなく、コードの可読性を高め、メンテナンス性を向上させる役割を担っています。
for文の基本構文と書き方
for文の構造は、一見すると複雑に見えるかもしれませんが、役割を3つに分けて考えると非常にシンプルです。
まずは、基本的な構文を確認しましょう。
for (初期化式; 条件式; 変化式) {
// 繰り返したい処理
}
この3つの式は、セミコロン ; で区切られており、それぞれがループの制御において重要な役割を果たします。
初期化式
初期化式は、ループを開始する前に一度だけ実行される式です。
通常は、ループの回数を数えるための変数(ループカウンタ)を宣言し、初期値を代入します。
例えば、int i = 0; のように記述します。
C99規格以降のC言語では、この初期化式の中で変数を宣言することが可能になりました。
これにより、変数 i のスコープ(有効範囲)をfor文の中に限定でき、予期せぬバグを防ぐことができます。
条件式
条件式は、各ループの開始前に評価されます。
この式の評価結果が「真(0以外)」であればループ内の処理を実行し、「偽(0)」であればループを終了します。
例えば、i < 10 と記述した場合、変数 i が10より小さい間はループが継続されます。
もし最初から条件が偽であれば、ループ内の処理は一度も実行されません。
変化式
変化式は、ループ内の処理が一通り終わった直後に実行されます。
一般的には、ループカウンタの値を増やしたり(インクリメント)、減らしたり(デクリメント)するために使用します。
例えば、i++ と記述すれば、1回のループが終わるごとに i の値が1ずつ増加します。
この変化によって、いずれ条件式が偽となり、無限ループを防ぐ仕組みになっています。
for文の実行フローを詳しく解説
for文がどのように動作しているのか、その内部的なステップを順番に見ていきましょう。
プログラムの挙動を正しく把握することは、デバッグ能力の向上に直結します。
| ステップ | 動作内容 | 詳細 |
|---|---|---|
| 1 | 初期化式の実行 | ループ開始時に一度だけ実行される。 |
| 2 | 条件式の評価 | 真ならステップ3へ、偽ならループ終了。 |
| 3 | ループ内処理の実行 | 中カッコ {} 内のプログラムが動く。 |
| 4 | 変化式の実行 | ループカウンタの更新などを行う。 |
| 5 | ステップ2に戻る | 再び条件をチェックする。 |
このように、「条件チェック → 実行 → 更新」というサイクルを繰り返すのがfor文の特徴です。
初心者が間違いやすいのは、変化式が実行されるタイミングです。
変化式はループ処理の「後」に実行されるため、最後のループ処理が終わった後にカウンタが更新され、その後の条件チェックでループを抜けるという流れになります。
実践的なfor文の使い方例
それでは、具体的なソースコードを用いてfor文の活用方法を見ていきましょう。
0から9まで数値を表示する
最も基本的な例です。
#include <stdio.h>
int main(void) {
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
return 0;
}
このコードでは、まず i = 0 で初期化され、i < 10 が真であるため printf が実行されます。
その後、i++ によって i が1になり、再び条件チェックが行われます。
最終的に i が10になった時点で条件式が偽となり、ループを抜けます。
数値を減算していくループ
for文は増やすだけでなく、減らすことも可能です。
for (int i = 10; i > 0; i--) {
printf("%d ", i);
}
この場合、10から始まり、1ずつ減っていき、1が表示された後に i が0になったタイミングで終了します。
カウントダウンなどの処理を実装する際に便利です。
指定したステップで値を変化させる
必ずしも1ずつ変化させる必要はありません。
2ずつ増やして偶数のみを扱うといった制御も可能です。
for (int i = 0; i <= 20; i += 2) {
printf("%d ", i);
}
i += 2 とすることで、0, 2, 4… と2おきに値を処理できます。
配列とfor文の密接な関係
C言語において、for文が最も頻繁に使われる場面の一つが配列の操作です。
配列のインデックス(添え字)は0から始まるため、for文のカウンタ変数と非常に相性が良いのです。
#include <stdio.h>
int main(void) {
int scores[] = {80, 90, 75, 60, 85};
int sum = 0;
int n = sizeof(scores) / sizeof(scores[0]);
for (int i = 0; i < n; i++) {
sum += scores[i];
}
printf("合計点: %d\n", sum);
return 0;
}
上記の例では、sizeof 演算子を用いて配列の要素数を取得し、その数だけループを回しています。
配列の全要素を走査して合計値を求めたり、特定の値を検索したりする処理は、プログラミングにおける定石です。
ループ制御:breakとcontinue
for文の途中でループを強制終了したり、特定の回だけ処理をスキップしたりしたい場合があります。
そのような時に使用するのが break 文と continue 文です。
break文による強制終了
break 文が実行されると、その時点でループ全体を即座に終了し、for文の次の命令へ進みます。
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // iが5になったらループを抜ける
}
printf("%d ", i);
}
// 出力結果: 1 2 3 4
特定の条件を満たした時点で探索を打ち切りたい場合などに非常に有効です。
continue文による処理のスキップ
continue 文が実行されると、ループ内のそれ以降の処理を飛ばして、次の「変化式」へジャンプします。
for (int i = 1; i <= 5; i++) {
if (i == 3) {
continue; // 3の時だけprintfをスキップ
}
printf("%d ", i);
}
// 出力結果: 1 2 4 5
エラーが発生したデータだけを除外して処理を続けたい場合などに重宝します。
二重ループ(多重ループ)の構造
for文の中にさらにfor文を記述することを「入れ子(ネスト)」と呼びます。
これは、二次元的なデータ処理(行列の計算や九九の表など)を行う際に不可欠なテクニックです。
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
printf("%2d ", i * j);
}
printf("\n"); // 外側のループが1回終わるごとに改行
}
二重ループでは、「外側のループが1回回る間に、内側のループが最初から最後まで回る」という動きを理解することが重要です。
九九の例では、i が1の時に j が1から9まで動き、次に i が2になってまた j が1から9まで動く、という流れになります。
無限ループの作成と対処法
意図的に、あるいは誤って終了条件を満たさないループを作ってしまうことがあります。
これを無限ループと呼びます。
無限ループの書き方
C言語でfor文を使って無限ループを作る最も一般的な書き方は以下の通りです。
for (;;) {
// 永久に繰り返される処理
}
初期化式、条件式、変化式のすべてを空にすると、条件式は常に真であるとみなされます。
組み込みシステムの制御プログラムや、ユーザーの入力待ち受けなどで意図的に使われることがあります。
無限ループからの脱出
意図的な無限ループの場合、必ず内部に break 文を配置し、特定の条件で抜け出せるように設計しなければなりません。
int count = 0;
for (;;) {
if (count > 100) {
break;
}
count++;
}
もし意図せず無限ループに陥ってしまった場合は、コンソール上で Ctrl + C を押すことでプログラムを強制終了できます。
開発中は、条件式が正しく評価されているか、変化式でカウンタが正しく更新されているかを常に確認する習慣をつけましょう。
for文とwhile文の使い分け
C言語にはもう一つの代表的なループ構文として while 文があります。
どちらを使っても同じ処理を書くことは可能ですが、一般的には以下のように使い分けます。
- for文を使うべき場面
繰り返す回数が決まっている。
カウンタ変数を使用して、規則的に値を変化させる。
配列の要素を順番に処理する。
- while文を使うべき場面
繰り返す回数が決まっていない(特定の条件が満たされるまで続けたい)。
ユーザーの入力内容に応じて終了するか決めたい。
ファイルの終端に達するまで読み込みたい。
for文は「構造的」であり、初期化から更新までの流れが一箇所にまとまっているため、カウンタに関連するバグ(更新忘れなど)が発生しにくいというメリットがあります。
for文における注意点とよくあるミス
プログラミング初心者だけでなく、中級者でも陥りやすいfor文の注意点をいくつか挙げます。
セミコロンの位置に注意
よくあるミスとして、for文の末尾にセミコロンを付けてしまうパターンがあります。
for (int i = 0; i < 10; i++); // ここにセミコロンを付けると...
{
printf("%d", i);
}
このように書いてしまうと、for文は「何もしない処理」を10回繰り返して終了し、その後のブロック {} はループとは無関係に一度だけ実行されることになります。
これはコンパイルエラーにはなりにくいため、論理エラーとして発見が遅れる原因になります。
浮動小数点数(float/double)の利用を避ける
ループカウンタに float や double を使うのは推奨されません。
for (double d = 0.0; d != 1.0; d += 0.1) { ... }
コンピュータ内部では浮動小数点数は誤差を含んで保持されるため、d != 1.0 という条件が永遠に真にならず、無限ループに陥る可能性があります。
ループカウンタには必ず整数型(intなど)を使用しましょう。
境界値のミス(オフバイワン・エラー)
ループを何回回すべきか、条件式で < を使うか <= を使うかによって、実行回数が1回ずれてしまうことがあります。
これを「オフバイワン・エラー」と呼びます。
配列の範囲外アクセスを引き起こし、プログラムをクラッシュさせる原因になるため、境界値のテストは慎重に行う必要があります。
高度なテクニック:複数の変数を制御する
あまり多用はされませんが、for文の初期化式や変化式には、カンマ演算子を使って複数の式を記述することができます。
for (int i = 0, j = 10; i <= 10; i++, j--) {
printf("i:%d, j:%d\n", i, j);
}
この例では、i を増やしながら同時に j を減らしていく、といった複雑な制御を一つのfor文で行っています。
ただし、詰め込みすぎるとコードの可読性が著しく低下するため、複雑になる場合はループ内で処理を分けることも検討してください。
まとめ
C言語のfor文は、単純な繰り返しのための道具に留まらず、配列操作やアルゴリズムの実装において中心的な役割を果たす極めて重要な構文です。
本記事で解説した以下のポイントを心に留めておきましょう。
- 初期化・条件・変化の3要素を正確に理解する。
- 配列のインデックス操作にはfor文が最も適している。
- ループの制御には
breakとcontinueを使い分ける。 - 浮動小数点数によるカウンタ管理は避け、整数を使用する。
- 無限ループの作成時は必ず脱出条件(break)を用意する。
これらの基本をマスターすれば、より複雑なデータ構造やアルゴリズムへの応用が可能になります。
まずは様々なパターンで自分でコードを書き、その挙動を確かめてみることから始めてみてください。
繰り返し練習することこそが、プログラミング習得の最短ルートです。






