从0开始记数经常被作为一个人是一名程序员的象征,在大多数主流编程语言中数组的记数都是以0为首位,今天读了 Dijkstra 的一篇旧文结合我的理解来谈谈为什么数组记数从0开始。

首先使用 0 作为数组第一位并不一定是一个正确的做法, 事实上也有以 1 作为首位的编程语言存在(Matlab,Fortran, Lua等),在 Dijkstra 的文章里他提出的证明思路是这样的:为表示一段离散的自然数集合例如 [4, 5, 6] 可以使用的公式有四种:
a. 4 ≤ i < 7
b. 3 < i ≤ 6
c. 4 ≤ i ≤ 6
d. 3 < i < 7

这四种表达方式的含义是一样的,那么他们之间是否有优劣之分? 是有的,考虑如果数值中包含自然数的最小值,那么 bd 的表达方式中下界就要使用非自然数这样是不完美的,所以首先排除。其次考虑 ac 如果这个集合是空集,用 c 是无法表达的(右侧的值大于等于左侧),于是就得到表达集合的最佳方式 4 ≤ i < 7.

对于包含 N 个元素的数组 array[i] 来说,对比下表的两种取值,从1开始记数是 1 ≤ i < N+1, 另一种使用更多的是 0 ≤ i < N, 后者看上去更 nice,并且每个元素的下标值等于在他之前元素的个数。

Dijkstra 是典型的计算机科学家,研究算法(Dijkstra’s algorithm)的学院派。在论证过程中的看上去更好和下标值等于之前元素个数都是很理论性的偏好,说不上是严格证明,事实上在实际使用过程中以 0 开头的数组取最后一个元素时 array[lengh-1] 才是更常见的 ugly 做法,所以在 Cocoa 里 NSArray 很早就有了 lastObject 这个方法。

虽然 Dijkstra 提供的论证不一定令人信服,以0作为首个元素记数还有其他一些原因:

对于 C 语言来说数组即指针,以 0 为首位那么 a 和 a[0] 就代表同一个值,不需要增加移动操作或者数值计算,这很可能是起初 C 会选择以 0 开始记数的原因。

另外对于求模运算,以 0 开始记数的数组在形式上会更整齐。

最后,自然数里的自然是一种理论上的自然,用0个回答冰箱里能装几个大象比装不了在形式上要统一很多,并且 0 真的是一个自然数。