为什么索引在“C”中以零开始?
为什么数组中的索引从C开始,而不是1?
在C中,数组的名称本质上是一个指针,指向一个内存位置,所以expression式array [n]指向一个内存位置n元素远离起始元素。 这意味着索引被用作偏移量。 数组的第一个元素完全包含在数组引用的内存位置(0个元素之外),所以它应该表示为array [0]。
更多信息:
http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html
这个问题是一年前发布的,但是这里有…
关于上述原因
虽然Dijkstra的文章 (以前在一个现在被删除的答案中引用)从math的angular度来看是有意义的 ,但是在编程方面却没有那么相关 。
语言规范和编译器devise人员所做出的决定是基于计算机系统devise人员决定从0开始计算的。
可能的原因
丹尼•科恩(Danny Cohen)从“ 争取和平”引用。
- IEEE链接
- IEN-137
对于任何基数b,只有在编号从0开始时,第一个b ^ N非负整数才由正数N位(包括前导零)表示。
这可以很容易地testing。 以2为底数,取2^3 = 8
第8位数字为:
- 8(二进制:1000)如果我们从1开始计数
- 7(二进制:111),如果我们开始计数为0
111
可以用3
位表示,而1000
则需要一个额外的位(4位)。
为什么这是相关的
计算机内存地址有2^N
单元寻址的单元。 现在,如果我们从1开始计数, 2^N
单元将需要N+1
地址线。 精确地访问1个地址需要额外的位。 (在上述情况下为1000
)。 解决这个问题的另一种方法是让最后一个地址不可访问,并使用N
地址线。
两者都不是最佳的解决scheme ,相比起始数为0,这将保持所有的地址访问,正好使用N
地址线!
结论
从0
开始计数的决定已经渗透到所有的数字系统 ,包括运行在其上的软件,因为它使代码转化为底层系统可以解释的简单。 如果不是这样,那么在机器和编程器之间会有一个不必要的翻译操作,对于每个数组访问。 它使编译更容易。
从报纸引用:
因为0是指向数组头的指针到数组的第一个元素有多远。
考虑:
int foo[5] = {1,2,3,4,5};
要访问0我们做:
foo[0]
但是foo分解成一个指针,上面的访问有类似指针的算术方式来访问它
*(foo + 0)
这些天指针算术不常用。 回头的时候,这是一个方便的方式,从一个地址,并从该起点移动X“整数”。 当然,如果你想留在原地,你只需加0!
因为基于0的索引允许…
array[index]
…被实施为…
*(array + index)
如果index为1,编译器将需要生成: *(array + index - 1)
,而这个“-1”会损害性能。
因为它使编译器和链接器更简单(更容易编写)。
参考 :
“…通过地址和偏移量引用内存直接在硬件上performance为几乎所有的计算机体系结构,因此C中的这个devise细节使得编译更容易”
和
“…这使得更简单的实现…”
出于同样的原因,星期三有人问你星期三有多less天,你说0而不是1,而当星期三有人问你到星期四有多less天时,你说1而不是2。
对从1开始而不是从0开始的数组编号是针对math思维严重不足的人。 当然,select错误的数组编号,这将会使编写一个好的程序变得非常困难。
我已经读过的基于零的编号的最优雅的解释是观察值不是存储在数字行的标记位置,而是存储在它们之间的空间中。 第一个项目被存储在0和1之间,下一个在1和2之间等等。第N个项目被存储在N-1和N之间。项目的范围可以使用任一侧的数字来描述。 个别项目按照惯例使用下面的数字进行描述。 如果给定一个范围(X,Y),使用下面的数字标识单个数字意味着可以识别第一个项目而不使用任何算术(它是项目X),但是必须从Y中减去一个来标识最后项目(Y -1)。 使用上面的数字识别项目可以更容易地识别范围内的最后一个项目(这将是项目Y),但很难识别第一个(X + 1)。
虽然根据上面的数字来确定项目并不可怕,但是将范围(X,Y)中的第一个项目定义为X之上的项目通常比将其定义为下面的项目(X + 1)。
技术原因可能是由于指向数组内存位置的指针是数组第一个元素的内容。 如果声明索引为1,那么程序通常会将该值添加到指针以访问不是您想要的内容的指针。
尝试使用基于1的matrix上的X,Y坐标访问像素屏幕。 这个公式非常复杂。 为什么复杂? 因为你最终将X,Y坐标转换成一个数字,偏移量。 为什么你需要将X,Y转换为偏移量? 因为这就是内存在计算机内部的组织方式,因为它是连续的内存单元(数组)。 计算机如何处理arrays单元? 使用偏移量(第一个单元格的位移,一个基于零的索引模型)。
因此,在需要(或者编译器需要)的代码中的某个时刻,将1基公式转换为基于0的公式,因为这就是计算机处理内存的方式。
数组索引总是从零开始。假设基地址是2000.现在arr[i] = *(arr+i)
。 现在if i= 0
,这意味着*(2000+0
)等于arrays中第一个元素的基地址或地址。 此索引被视为偏移量,所以默认索引从零开始。
数组名是一个指向基地址的常量指针。当你使用arr [i]时,编译器将它作为*(arr + i)来处理。由于int的范围是-128到127,所以编译器认为-128到-1是负数和0到128是正数。所以数组索引总是从零开始。
因为当我们访问数组元素时,下面的公式被编译器使用((基地址)+ index * size)fisrt元素总是被存储在数组的基地址中…所以如果我们从1开始,我们不能访问第一个元素, sesond元素的地址…所以它从0开始。