C言語のプログラミングにおいて、ループ処理は特定の条件が満たされるまで処理を繰り返すための基本的な構造です。
その中でも「無限ループ」は、意図的にプログラムを終了させずに継続して実行させる手法として、システム開発や組み込み開発、サーバーサイドのプログラムなどで非常に重要な役割を果たします。
一方で、初心者が誤って無限ループを作ってしまうと、CPUリソースの過剰消費やフロン(フリーズ)の原因となり、バグとして扱われることも少なくありません。
本記事では、C言語における無限ループの代表的な書き方であるwhile文やfor文の使い方から、安全にループを抜ける方法、そして実戦で使える注意点までを網羅的に解説します。
無限ループを「制御可能なツール」として使いこなせるよう、詳細なロジックを学んでいきましょう。
C言語における無限ループの定義と役割
無限ループとは、その名の通り「終了条件が常に真であるため、永遠に繰り返されるループ構造」を指します。
C言語のプログラムは通常、main関数の末尾に到達するか、明示的に終了命令が出されたときに停止しますが、特定のアプリケーションではプログラムを常に動かし続ける必要があります。
例えば、以下のようなケースで無限ループは必須となります。
- OSのカーネルや常駐プログラム(デーモン):システムの監視や要求待ちを常に行う。
- 組み込みシステム:家電製品やマイコンにおいて、電源が切れるまでセンサーの読み取りや制御を繰り返す。
- ゲームエンジン:ユーザーの入力を受け付け、画面を更新し続ける「ゲームループ」を維持する。
- ネットワークサーバー:クライアントからの接続リクエストを常に待ち受ける。
このように、無限ループは決して「間違い」ではなく、目的を持って設計される重要な制御構造なのです。
while文を使った無限ループの書き方
C言語で最も直感的で頻繁に使われる無限ループの書き方は、while文を利用する方法です。
while文は、カッコ内の条件式が「真(0以外)」である限り処理を継続します。
while(1) による標準的な書き方
C言語において、数値の「1」は「真」を意味します。
したがって、条件式に 1 を指定すると、常に条件が成立しているとみなされ、無限ループが形成されます。
#include <stdio.h>
int main() {
while (1) {
printf("このメッセージは永遠に表示されます\n");
}
return 0;
}
このコードでは、whileの条件が常に 1 であるため、波括弧内の処理が止まることなく実行されます。
C言語の慣習として、while(1)は「意図的な無限ループ」であることを示す最も一般的な記述です。
stdbool.h を使用した while(true)
C99規格以降では、stdbool.hヘッダーをインクルードすることで、bool型や true / false というキーワードが使用可能になります。
これにより、可読性を高めることができます。
#include <stdio.h>
#include <stdbool.h>
int main() {
while (true) {
printf("論理値を使用した無限ループです\n");
}
return 0;
}
while(true)と書くことで、数値の 1 を使うよりも「条件が成立し続けている」という意味が明確になります。
モダンなC言語のコーディング規約を採用しているプロジェクトでは、こちらの形式が好まれることもあります。
for文を使った無限ループの書き方
for文を使用しても無限ループを作成することができます。
for文は一般的に「回数が決まっているループ」に使われますが、特定の記述をすることで無限ループとして機能します。
for(;;) による省略記法
for文の構文は for(初期化式; 条件式; 変化式) ですが、これらの式はすべて省略可能です。
特に、中央の条件式を省略すると「常に真」として扱われるという仕様があります。
#include <stdio.h>
int main() {
for (;;) {
printf("for文による無限ループです\n");
}
return 0;
}
for(;;)は、古くからのC言語プログラマーの間でよく使われる表現です。
一部のコンパイラでは、while(1)と書くと「定数による条件分岐」として警告を出すことがありますが、for(;;)はそのような警告を避けられるというメリットがあります。
for文とwhile文の使い分け
どちらの書き方を使っても動作に大きな差はありませんが、プロジェクトのスタイルガイドに従うのが一般的です。
| 記述方法 | 特徴 |
|---|---|
while(1) | 最も一般的で、意味が伝わりやすい。 |
while(true) | モダンな書き方で、可読性が高い(要 stdbool.h)。 |
for(;;) | コンパイラの警告を避けやすく、伝統的なCスタイル。 |
いずれにせよ、チーム内で統一された記法を用いることがコードの品質維持につながります。
無限ループから安全に抜ける方法
無限ループは「永遠に終わらない」ことが前提ですが、実際のプログラムでは特定の条件(ユーザーの停止操作やエラー発生など)でループを抜ける必要があります。
ここでは、ループを制御するためのキーワードを解説します。
break文による脱出
break文は、実行中のループを強制的に終了させ、ループの次の行に制御を移す命令です。
#include <stdio.h>
int main() {
int count = 0;
while (1) {
printf("カウント: %d\n", count);
if (count >= 10) {
break; // countが10になったらループを抜ける
}
count++;
}
printf("ループを抜けました\n");
return 0;
}
このように、if文と組み合わせて「特定のフラグが立った時」や「カウントが上限に達した時」にループを止めるのが最も基本的な手法です。
return文による関数ごと終了
ループを抜けるだけでなく、そのループが含まれている関数自体の処理を終わらせたい場合は、return文を使用します。
void checkInput() {
char input;
while (1) {
scanf(" %c", &input);
if (input == 'q') {
return; // 関数そのものを終了して呼び出し元に戻る
}
}
}
main関数内で return 0; を実行すれば、プログラム全体が終了します。
exit()関数によるプログラムの強制終了
重大なエラーが発生した場合など、ループや関数に関係なくプログラムを即座に終了させたい場合は、stdlib.hに含まれる exit() 関数を使用します。
#include <stdlib.h>
if (critical_error) {
exit(EXIT_FAILURE); // プログラムを即座に異常終了させる
}
goto文による脱出(多重ループの場合)
通常、goto文の使用は推奨されませんが、多重ループを一気に抜け出す場合に限っては、breakよりも簡潔に記述できるため、例外的に許容されることがあります。
for (;;) {
for (;;) {
if (condition) {
goto label;
}
}
}
label:
printf("多重ループから脱出しました\n");
ただし、プログラムの構造が複雑になりやすいため、使用は最小限にとどめましょう。
無限ループ実装時の注意点とリスク
無限ループを実装する際には、コンピュータのリソース管理に細心の注意を払う必要があります。
適切な考慮を欠いた無限ループは、システム全体のパフォーマンスを著しく低下させます。
CPU使用率100%問題の回避
何も制御せずに空の、あるいは非常に高速な処理を行う無限ループを回すと、CPUの1つのコアが100%占有されてしまいます。
これはPCの発熱やバッテリー消費の増大、他のプログラムの動作遅延を引き起こします。
これを防ぐためには、1回のループごとにわずかな待ち時間を挿入することが重要です。
- Windowsの場合:
Sleep(ミリ秒)(windows.hが必要) - UNIX/Linuxの場合:
usleep(マイクロ秒)(unistd.hが必要)
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
while (1) {
// 処理を実行
#ifdef _WIN32
Sleep(10); // 10ミリ秒待機
#else
usleep(10000); // 10,000マイクロ秒(10ミリ秒)待機
#endif
}
このように待機を入れることで、CPUの負荷を劇的に抑えることができます。
メモリリークへの警戒
無限ループ内で動的にメモリを確保(mallocなど)し、それを解放(free)し忘れると、プログラムが動き続ける限りメモリ消費量が増大し続けます。
これをメモリリークと呼び、最終的にはシステムがメモリ不足でクラッシュする原因となります。
無限ループ内でのメモリ割り当ては最小限にし、必ず適切なタイミングで解放するように設計してください。
意図しない無限ループ(バグ)の発見方法
意図せず無限ループに陥ってしまった場合、プログラムが応答しなくなります。
開発中にこのような事態になったら、以下の方法で対処します。
- Ctrl + C:コンソール上で実行しているプログラムを強制終了させる標準的なコマンドです。
- デバッガの活用:
gdbなどのデバッガを使用し、実行を一時停止(ブレーク)して、現在どの行をループしているかを確認します。 - ログ出力:ループの開始時に変数の値を表示させ、条件式が正しく評価されているかを確認します。
特に、ループの継続条件に使っている変数が、ループ内で正しく更新されていない(インクリメント忘れなど)ケースは非常に多いバグのパターンです。
実践例:ユーザー入力を待ち受ける無限ループ
より実践的な例として、ユーザーが「exit」と入力するまでコマンドを受け付け続ける簡単なシェル風のプログラムを見てみましょう。
#include <stdio.h>
#include <string.h>
int main() {
char command[100];
printf("コマンド入力待ち(終了するには 'exit' と入力):\n");
while (1) {
printf("> ");
if (scanf("%99s", command) == EOF) break;
if (strcmp(command, "exit") == 0) {
printf("プログラムを終了します。\n");
break;
} else if (strcmp(command, "hello") == 0) {
printf("こんにちは!\n");
} else {
printf("不明なコマンド: %s\n", command);
}
}
return 0;
}
この例では、ユーザーの入力を無限に待ち続け、特定の文字列(exit)が入力された時のみループを抜ける構造になっています。
これはCLI(コマンドラインインターフェース)ツールの基本形です。
まとめ
C言語における無限ループは、適切に設計・管理することで非常に強力な武器となります。
while(1)やfor(;;)といった書き方は、いずれも無限の実行を保証しますが、それと同時に「どのようにして安全にループを抜けるか」を常にセットで考える必要があります。
今回のポイントを整理すると以下の通りです。
- 無限ループには
while(1)またはfor(;;)を使用する。 - ループを抜けるには
breakやreturnを適切に配置する。 - CPU負荷を抑えるために、適切なスリープ処理を入れる。
- メモリリークや変数の更新忘れなど、意図しないループに陥らないよう注意する。
無限ループをマスターすることは、OSに近い低レイヤーのプログラミングや、高度なリアルタイムシステムを開発するための第一歩です。
バグとしての無限ループを避け、制御された無限ループを実装できるよう、日々のコードに活かしてください。






