# 為什麼索引值從 0 開始算？

> 說明程式語言陣列索引值從 0 開始的原因。文中介紹索引值在記憶體運作中代表「偏移量」的概念，並透過 Python 串列示範如何利用起始位置、元素大小與索引值計算出精確的記憶體位址。雖然 Lua 與 R 語言選擇從 1 開始，但多數主流語言仍沿用 0 為起點的慣例，本文將說明這項技術背景與計算邏輯。

Published: 2024-03-03
URL: https://kaochenlong.com/why-array-index-begin-with-zero

---

有沒有想過為什麼我們學的數學是從 1 開始算，但好像大部份比較主流的程式語言的陣列包括 Python 的串列，索引值卻是從 0 開始的？因為這是因為陣列的索引值並不是指向元素本身，比較像是記憶體位置的「偏移量」。

假設有一個陣列像這樣：

```py
chars = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;]
```

當我們說「變數 `chars` 指向 `[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;]` 陣列」的時候，並不是 `chars` 這個變數直接指向這一整個陣列，而是 `chars` 變數指向這個陣列的「起始位置」，更精準的說是記憶體位置。陣列在記憶體裡的位置跟門牌號碼一樣都是連號的，假設這個陣列的起始記憶體位置是 `1450`，然後每個元素所佔的位置或說格子的大小我就先隨便假設是 8（先不管單位跟以及為什麼是 8）。大概示意圖如下：

![為什麼索引值從 0 開始](/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBbGNFIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--8109960ab9baffa3dcdf08a13a7650daf10a5e1f/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBPZ2h3Ym1jNkZISmxjMmw2WlY5MGIxOXNhVzFwZEZzSGFRSUFCV2tDQUFRPSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--8d2325c9396bfea89fddf1a08b3bb210edeb12c8/index-of-array.webp)

這樣的話，你認為要怎麼取得第一個元素的 `a` 字元？不就是指向 `1450` 的位置就拿到了嗎？（你也可以說是從 `1450` 到 `1458` 這一塊空間）。

我們現在知道怎麼拿第一個元素了，接著要怎麼拿第二個？其實只要知道第一個元素的位置再搭配簡單的數學加法跟乘法就能算出來了：

&gt; 起始位置 + (1 x 8) = 1458

同理可證，第三個、第四個直到第 N 個元素就能推導出計算公式：

&gt; 起始位置 + (N x 8)

到這裡，大家有看出來上面公式裡的 `N`，剛好就是等於我們平常在講的索引值嗎？所以索引值其實就是記憶體位置的「偏移量」，因此才會從 0 開始算。

所以陣列索引值從 0 開始的概念從滿早期的程式語言開始就有了，大家用著用著也習慣了，Python 以及其它程式語言也都受到影響，所以 Python 的串列索引值也跟是從 0 開始算。

事實上，也不是所有程式語言的索引值都是從 0 開始算的，不同的程式語言對這件事有不同的觀點，像程式語言 [Lua](https://www.lua.org/)、[Fortran](https://fortran-lang.org/)、[COBOL](https://zh.wikipedia.org/zh-tw/COBOL)、[Julia](https://julialang.org/) 跟 [R 語言](https://www.r-project.org/)等都是從 1 開始算的，也許在他們的觀點來看，`chars[1]` 就是第一個或第一欄，看起來更簡單、直覺。

