配列の添字を1つずらしてしまうoff-by-oneバグ
配列の要素数と添字の範囲を混同し、ループの開始や終了条件を1つずらしてしまうバグです。要素が抜けたり、逆に範囲外を読んでしまったりします。
なぜエラーが出ないのか
出力: 170
(エラーなし)- C++は何も報告しません。コンパイルも実行も正常に完了するためです
出力: 170- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <iostream> 2 int main() { 3 int scores[3] = {70, 80, 90}; 4 int sum = 0; 5 for (int i = 1; i < 3; i++) { ^ 6 sum += scores[i]; 7 } 8 std::cout << sum << std::endl; 9 return 0; 10 }
出力: 170期待: 240
ループをi=1から始めると、添字0の要素(70)が合計に含まれません。配列の最初の要素は添字0であることを忘れると起きるミスです。
直し方: 1 を 0 にします。
広告
広告スロット(未設定)
パターン2
1 #include <iostream> 2 int main() { 3 int prices[4] = {10, 20, 30, 40}; 4 int total = 0; 5 for (int i = 0; i < 3; i++) { ^ 6 total += prices[i]; 7 } 8 std::cout << total << std::endl; 9 return 0; 10 }
出力: 60期待: 100
要素数4の配列なのに境界をi<3にすると、最後の要素(40)が合計に含まれません。有効な添字は0〜3までなので、境界には要素数そのものを使います。
直し方: 3 を 4 にします。
パターン3
1 #include <iostream> 2 int main() { 3 int temps[5] = {18, 20, 19, 21, 17}; 4 int count = 4; ^ 5 int sum = 0; 6 for (int i = 0; i < count; i++) { 7 sum += temps[i]; 8 } 9 std::cout << sum << std::endl; 10 return 0; 11 }
出力: 78期待: 95
countを要素数5より1少ない4にすると、最後の要素(17)が合計から抜け落ちます。要素数を数える変数は実際の要素数と一致させる必要があります。
直し方: 4 を 5 にします。
よくある誤解
「配列の要素数がNならインデックスも1からNまで」というのは誤解です。C++(C系言語共通)の配列の添字は0から始まり、末尾はN-1です。この前提がずれると必ずoff-by-oneが起こります。
まとめ
配列の添字を1つずらしてしまうoff-by-oneバグは初級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。