为什么 C 语言数组是从 0 开始计数的?

C 语言等大多数编程语言的数组从 0 开始而不从 1 开始,有两个原因:

第一:地址计算更方便

C 语言从 0 开始的话,array[i] 的地址就正好是:

(array + i) 

如果是从 1 开始的话,就是

(array + i - 1) 

多一次计算,性能受影响,再扩展到二维数组的话 array[i][j] 从 0 开始的地址是:

(array + i * N + j) 

多整洁,而从 1 开始要变成

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

更繁琐。并且用 1 开始的话,同一个地址用 “指针+偏移”寻址和用 “数组+下标” 寻址还不能统一,经常要换算,何必呢?

第二:计算机硬件系统就是从 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 解释过编程语言这么做的原因只是遵从硬件设计:

The decision taken by the language specification & compiler-designers is based on the decision made by computer system-designers to start count at 0.

所以 C 语言数组从零开始,目的在于:1)性能更好;2)统一数组和指针寻址;3)遵从硬件寻址法。

除此之外还有一些理论上的原因。

第三:数学上的原因

除去数组索引外,Dijkstra 主张一切计数应该从 0 开始,并且写了一篇文章解释:

(点击 more/continue 继续)

Dijkstra: Why numbering should start at zero

他明确的批过 Fortran 和 Pascal 等从 1 开始的早期语言考虑不周:

他给出了无懈可击的理由,大概论点是,对于 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 < x 表示一个序列,你总要提供一个比第一个元素小一号的数字,不但恶心,往往不可能(存在最小的有理数,不存在最大有理数),所以 a <= x 的表述更好;
  • 对于右边 x < b 的表述比 x <= b 的表述更好,因为当 a = b 时,a <= x < b 可以表示一个空集,而 a <= x <= b 无法表示一个空集
  • 方案 a) 和方案 b) 可以一眼看出序列的长度。
  • 方案 a) 和方案 d) 更容易表述邻接的序列。

如此证明左闭右开的方案 a) a <= x < b 更适合表述表述一个序列。

Dijkstra 论证完 a <= x < b 更是更好的选择后,给出结论,长度为 N 的数组从 0 开始更好,因为 0 <= x < N 的表述比 1 <= x < N+1 更清晰。

扩展阅读:

别被忽悠了 Lua 数组真的也可以从 0 开始索引?

<think>好的,用户想知道Python数组的索引是否从0开始。首先我需要确认Python的数组索引规则。根据参考资料,引用[1]提到大多数编程语言数组0开始,而FORTRAN和COMTRAN等从1开始。Python作为类C语言,应该遵循0起始索引。 然后,引用[2]的标题直接提到“python数组索引”,可能里面具体说明索引方式。但内容中的关键字如arange、array等函数都是Python中生成数组的方法,这些方法的索引应该都是从0开始。比如numpy数组的索引也是0起始的。 另外,引用[3]是关于如何在Python中查找数组索引的教程,里面应该提到索引的起始位置。用户提供的链接内容可能进一步确认了索引从0开始,比如访问第一个元素用索引0。 需要确保回答准确,并引用正确的资料。可能还需要举例说明,比如列表或numpy数组的索引示例,让用户更清楚。同时注意用户可能混淆列表和数组,需要明确说明Python中的列表(list)和数组(如numpy数组)都是从0开始索引的。 最后,根据用户的问题,生成相关问题,比如索引越界、负索引等,帮助用户扩展知识。</think>在Python中,数组(包括列表、元组和NumPy数组)的索引确实从0开始计数。这与C、Java等大多数编程语言保持一致,但不同于早期的FORTRAN或COBOL语言[^1]。 ### 具体说明 1. **基础索引规则** 假设有一个列表 `arr = [10, 20, 30, 40]`,其索引对应关系为: ``` 索引: 010 1 → 20 2 → 30 3 → 40 ``` 访问第一个元素需使用 `arr[0]`,第二个元素用 `arr[1]`,以此类推。 2. **底层原理** 从0开始的索引方式与内存地址计算直接相关。数组元素在内存中是连续存储的,元素地址计算公式为: $$ \text{地址} = \text{基地址} + \text{索引} \times \text{元素大小} $$ 这种设计避免了每次访问元素时的索引减1操作,提升效率[^1]。 3. **特殊索引支持** Python还支持负索引: - `arr[-1]` 表示最后一个元素(40) - `arr[-2]` 表示倒数第二个元素(30) ### 示例代码 ```python # 创建列表 fruits = ["苹果", "香蕉", "橙子", "芒果"] # 访问元素 print(fruits[0]) # 输出: 苹果 print(fruits[-1]) # 输出: 芒果 # 切片操作 print(fruits[1:3]) # 输出: ["香蕉", "橙子"] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值