为什么数组的索引在C中以零开头?
#编程 #linux #c #cpp

当今大多数编程语言,包括C,由于某些令人信服的原因,将基于零的索引用于数组。

更好的解决方案

如果C语言数组从0开始,则数组[i]的地址完全是:

(array + i)

这是非常一致的。但是,如果它从1开始,则数组的地址为:

(array + i - 1)

另外一项计算会影响性能,如果扩展到二维数组,情况甚至会更糟。

对于基于零的索引,array[i][j]的地址为

(array + i * N + j)

这很整洁。但是对于1个基于1的索引,array[i][j]的地址将成为:

(array + (i - 1) * N + (j - 1))

这会更加麻烦。此外,如果我们从1开始,则不能使用“指针 +偏移”和“ Array + Index”统一地解决相同的地址,并且通常需要转换。那么,为什么要打扰

计算机硬件设计为使用0作为起始索引

物理内存地址和端口都从0开始。例如,32位计算机内存的地址范围是:

[0, 2 ^ 32 - 1]

可以用32位整数表示。但是,如果内存从1开始解决,则32位计算机的地址范围为:

[1, 2 ^ 32]

在这种情况下,最高地址2 ^ 32将需要33位整数,这将浪费资源。

其他端口地址和DMA通道也从0原理开始。如果我们使用3位表示DMA频道,则最好表达8个频道(0-7),而从1个开始,相同的3位只能表达7个频道(1-7),这也是浪费资源。

因此,一种与系统接近的语言自然选择遵循硬件设置。除了第一点中提到的更简单的地址计算外,它还可以保持与计算机系统的一致性,并统一指针地址和数组地址的用户体验。

Dijkstra解释说,编程语言这样做的原因仅仅是遵循硬件设计决策:

语言规范和编译器设计师做出的决定是基于计算机系统设计师在0中开始计数的决定。

因此,由于以下原因,C语言阵列以零开始:1)更好的性能; 2)统一的数组和指针地址; 3)遵循硬件地址约定。

除了这些实际原因外,还有一些理论原因。

理论原因

除了数组索引外,Dijkstra提倡所有计数应从0开始,他写了一篇文章来解释此观点:

https://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF

他明确批评了诸如Fortran和Pascal之类的早期语言,这些语言是从1开始的,因为它不够考虑:

Image description

他给出了一个无可挑剔的原因,可能说有几种表达整数序列2、3、4,...,...,12的方法。

a)2 <= i < 13
b)1 < i <= 12
c)2 <= i <= 12
d)1 < i < 13

然后他解释了:

对于左侧,表达式“ a <= x”比“ a

对于右侧,表达式“ x

方案(a)和方案(b)都可以轻松显示序列的长度。

方案(a)和方案(d)更容易表达相邻序列。

因此,证明了左关闭和右开的方案(a)“ a <= x

Dijkstra认为“ A <= x