プログラミングを始めたばかりの人が最初に感じる違和感、それが「なぜ最初の要素が 1 番目ではなく 0 番目なのか?」という疑問です。 日常の感覚とはズレていますが、コンピュータの世界では 0 から始めることには、数学的にも構造的にも非常に強力なメリットがあります。
その理由を「メモリアドレス」と「計算の美しさ」の観点から紐解いてみます。
1. インデックスは「距離(オフセット)」である
これが最も本質的な理由です。 配列は、メモリ上の「連続した箱」の中にデータが並んでいます。コンピュータが特定の要素の場所を探すとき、裏側では次のような計算を行っています。
要素のアドレス = 先頭のアドレス + (インデックス × 要素のサイズ)
もし配列の先頭を 1 から始めると、この計算は毎回こうなります。
要素のアドレス = 先頭のアドレス + ((インデックス - 1) × 要素のサイズ)
毎回 - 1 をしなきゃいけない。
これはコンピュータにとって無駄な処理ですし、0 から始めれば「先頭のアドレス + 距離(インデックス)」という非常にシンプルな足し算だけで済みます。つまり、インデックス 0 は「先頭からの距離が 0」であることを意味しているのです。
2. 範囲の表現がスマートになる
0 始まりの配列において、長さn の配列の範囲を表現すると、数学的に非常に綺麗になります。
- インデックスの範囲:
0 <= i < n - スライスなどの範囲:
[start, end)(start は含み、end は含まない)
1 <= i <= n となり、引き算のあとに + 1 をしないと要素数が合いません。アルゴリズムを書く際、この「プラス 1」の有無がバグ(オフバイワンエラー)の原因になりやすいため、0 始まりの方が安全だと言えます。
3. 歴史的な継承(C 言語の影響)
現代の多くの言語(Java, Python, JavaScript など)が 0 始まりなのは、それらが C 言語 の設計を色濃く継承しているからです。
C 言語では、配列のインデックス指定a[i] は、ポインタ演算 *(a + i) の書き換え(シンタックスシュガー)に過ぎません。ポインタの足し算そのものが「先頭からのオフセット」を意味していたため、0 始まりが必然でした。
この設計があまりに合理的だったため、後発の言語もこれに従うのがデファクトスタンダードとなりました。
まとめ
「1 から数える」のは人間にとって自然ですが、「0 からオフセットを計算する」のはコンピュータにとって自然です。
- 0 は「先頭からの距離」を意味する
- 範囲計算の引き算が綺麗に決まる
- C 言語からの合理的な設計の継承
array[0] と書くときは、これがメモリ上の先頭アドレスをダイレクトに指し示している「距離 0」の場所なんだな、と思い浮かべてみてください。