トレースの本番はここです。繰り返しが入るとトレース表は一気に縦へ伸びますが、やることは今までと1ミリも変わりません。1行ずつ書くだけです。
1周は3つの部分でできている
繰り返しは、次の3つが順番に回っています。
- 条件判定 — 続けるか、抜けるか
- 本体 — 中身の処理
- 更新 — 次の周に向けて値を変える
int i = 1;
int sum = 0;
while (i <= 3) {
sum = sum + i;
i = i + 1;
}このプログラムを、下のビジュアライザで1ステップずつ追ってみてください。条件判定に戻るたび、i が増えているのが見えます。
周回番号の列を足すと迷わない
ループのトレース表には、「何周目か」の列を足すと見通しが良くなります。
周 | 行 | i | sum | 条件
---+----+---+-----+------
1 | 3 | 1 | 0 | 真
1 | 4 | 1 | 1 |
1 | 5 | 2 | 1 |
2 | 3 | 2 | 1 | 真
2 | 4 | 2 | 3 |同じ行番号が何度も出てくるのがループの特徴です。周の列があると、どこを見ているか見失いません。
最重要: 抜けた瞬間の値
トレース問題でいちばん狙われるのが、ループを抜けたあとの変数の値です。上の例では、i が4になったところで 4 <= 3 が偽になり、ループを抜けます。
つまり終了後の i は3ではなく4です。「3回まわったから3」と答えてしまう人が非常に多い箇所です。条件を偽にした値まで進んでいるからこそ、ループが終わったのだと考えてください。
繰り返しの回数を数え間違える罠
iが1から始まりi <= 3なら、1・2・3の3回iが0から始まりi < 3なら、0・1・2の3回iが1から始まりi < 3なら、1・2の2回
1つずれる間違いは、プログラミングで最も多いバグの一つで、英語圏では「オフ・バイ・ワン誤り」という専用の名前まで付いています。迷ったら数えず、トレース表を3行だけ書く。それが最短の解決法です。
全部書かなくてよい
100周するループを100行書く必要はありません。実務でも次のようにします。
- 最初の2〜3周をきちんと書く(始まり方を確かめる)
- 途中は「同じことが続く」と判断して飛ばす
- 最後の1〜2周と、抜けた直後を必ず書く(終わり方を確かめる)
バグは、たいてい始まりと終わりに潜んでいます。真ん中の繰り返しは、最初の数周が正しければ同じ形が続くだけです。この省略ができるようになると、トレースは驚くほど速くなります。
終わらないループの見つけ方
表を書いていて、何周しても条件の値が変わらないことに気づいたら、それは無限ループです。原因はほぼ決まっていて、更新(i = i + 1)を書き忘れたか、更新の向きが条件と逆かのどちらかです。実行する前に、紙の上で発見できます。