実行したら、画面が固まって返ってこない。カーソルだけが点滅している。初めてこれに出くわすと「壊した」と思うものですが、たいていは無限ループです。壊れてはいません。怖がるより、原因の型を覚えたほうが早く片付きます。
まず止め方から。実行中のコンソールで Ctrl + C を押せば中断できます。これを知っているだけで恐怖は半分になります。
無限ループの原因は、ほぼ3つの型に収まります。
型1: 更新を忘れた。 whileの中で、条件に使っている変数を動かしていない。
#include <stdio.h>
int main(void) {
int i = 0;
while (i < 5) {
printf("%d ", i);
// i++; ← これが無いと 0 が出続ける
}
return 0;
}型2: 更新はしているが、条件に近づかない。 i-- と書くつもりが i++ になっている、i = i + 1 のつもりが i + 1 だけ(計算しても代入していない)、あるいは条件がそもそも絶対に偽にならない(while (x != 3) に対して x が 2 ずつ増えていて 3 を飛び越す、など)。
型3: continueが更新を飛ばした。 前のトピックで見た while + continue の地雷です。
診断のコツは、疑わしいループの先頭に printf を1行入れて、条件に使っている変数の値を毎周表示させること。数字が動いていなければ型1か型3、動いているのに条件に近づかないなら型2です。原因が絞れれば、直すのは一瞬です。
ここまで悪者扱いしてきましたが、わざと終わらせないループもあります。ゲームのメインループ、組み込み機器の制御、サーバーの待ち受け——これらは電源が切れるまで回り続けるのが正しい姿です。
#include <stdio.h>
int main(void) {
int count = 0;
while (true) { // C23 なら true をそのまま書ける
count++;
if (count >= 3) {
printf("3回まわったので終わります\n");
break; // 出口は必ず用意する
}
}
return 0;
}while (true) や for (;;) が定番の書き方です。大事なのは、出口を必ず1つ用意すること。「条件で終わらせない」と決めたなら、代わりに break で終わらせる責任が生じます。出口の無い while (true) は、ただのバグです。
最後に、このトラックの総まとめとして FizzBuzz を書きましょう。1から15まで表示し、3の倍数なら Fizz、5の倍数なら Buzz、両方の倍数なら FizzBuzz にします。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 15; i++) {
if (i % 15 == 0) {
printf("FizzBuzz\n");
} else if (i % 3 == 0) {
printf("Fizz\n");
} else if (i % 5 == 0) {
printf("Buzz\n");
} else {
printf("%d\n", i);
}
}
return 0;
}forで回数を決めて回し、if / else ifを狭い条件から並べ、剰余で判定する。このトラックで学んだことが全部入っています。もし i % 3 == 0 を先頭に置いたら、15 は Fizz に吸い込まれて FizzBuzz は一度も表示されません。t06-03 で見た「順番の罠」が、ここでも顔を出すわけです。
ループを書く前のチェックを3つ、置いていきます。この条件は、どの行で偽になる? 条件に使う変数は毎周きちんと動いている? 最悪でも何周で終わる? 3つ目に答えられないループには、安全弁のカウンタを入れておくと安心です。