为什么索引以‘ C’开头?

为什么数组中的索引以 C 语言中的零开始而不是以1开始?

114520 次浏览

在 C 语言中,数组的名称实质上是一个指针 [但请看评论],一个对内存位置的引用,因此表达式 array[n]指的是远离开始元素的内存位置 n元素。这意味着索引用作偏移量。数组的第一个元素恰好包含在数组所引用的内存位置(0个元素之外)中,因此它应该表示为 array[0]

更多信息:

Http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html

技术原因可能源于这样一个事实: 指向数组内存位置的指针是数组第一个元素的内容。如果声明指针的索引为1,程序通常会将1的值添加到指针,以访问不是您想要的内容。

因为0是指向数组头部的指针到数组的第一个元素的距离。

考虑一下:

int foo[5] = {1,2,3,4,5};

要访问0,我们需要:

foo[0]

但是 foo 分解为一个指针,并且上面的访问具有类似的指针算术访问方式

*(foo + 0)

如今,指针算法的使用已经不那么频繁了。在很久以前,这是一种很方便的方法来获取一个地址并将 X“ int”从那个起点移开。当然,如果你只想呆在原地,你只需要加0!

因为它使编译器和链接器更简单(更容易编写)。

参考文献 :

通过地址和偏移量引用内存实际上在所有计算机架构的硬件中都直接表示,所以 C 语言的这个设计细节使编译变得更加容易

还有

“ ... 这使得一个更简单的实施...”

出于同样的原因,当今天是星期三,有人问你还有多少天到星期三,你说0而不是1,当今天是星期三,有人问你还有多少天到星期四,你说1而不是2。

因为从0开始的索引允许..。

array[index]

实施为。

*(array + index)

如果 index 是基于1的,编译器将需要生成: *(array + index - 1),而这个“-1”将会损害性能。

这个问题是一年前发布的,但现在..。


关于上述原因

虽然从数学角度来看,Dijkstra 的文章(以前在现已删除的 回答中引用过)是有意义的,但在编程方面,它是 没那么重要

语言规范和编译器设计者所做的决定是基于 计算机系统设计人员决定从0开始计数。


可能的原因

引自丹尼 · 科恩的 和平请求

对于任何基数 b,第一个 b ^ N 非负整数由正确的 N数字表示(包括 前导零) ,只有当编号从0开始。

这可以很容易地测试。在基数 -2,采取 2^3 = 8 第八个号码是:

  • 8(二进制: 1000) ,如果我们从1开始计数
  • 7(二进制: 111) ,如果我们从0开始计数

111可以使用 3位表示,而 1000需要额外的位(4位)。


这有什么关系

计算机内存地址的 2^N单元由 N位寻址。现在,如果我们从1开始计数,2^N细胞将需要 N+1地址线。正好访问1个地址需要额外的位。(在上述情况下为 1000。).另一种解决方法是保持最后一个地址不可访问,并使用 N地址行。

两者都是 次优解次优解次优解,相比之下,起始计数为0,这将保持所有地址的可访问性,正好使用 N地址行!


结论

0开始计数的决定已经渗透到了 所有数字系统,包括运行在它们上面的软件,因为它使得代码转换成底层系统可以解释的内容变得更加简单。如果不是这样,对于每个数组访问,机器和程序员之间就会有一个不必要的转换操作。它使编译更加容易。


引用报纸上的话:

谁在一垒? 0号还是1号

人们开始从数字一开始数。“ first”这个词被缩写为“1st”,表示“ one”。然而,这是一种非常现代的符号。旧的概念不一定支持这种关系。在英语和法语中,单词 第一不是从单词 派生出来的,而是从一个旧单词 王子派生出来的,意思是 最重要的。同样,英语单词 第二也不是从数字2派生出来的,而是从一个意为“跟随”的旧单词派生出来的显然,第三和第三,第四和第四,等等之间有着密切的关系。这些关系也出现在其他语系中。例如,在希伯来语中,第一来源于单词 ,意思是“最重要的”希伯来语中秒的单词来源于单词 two,这种序数名和基数名的关系适用于所有其他数字。很长一段时间以来,人们都是从一开始计数,而不是从零开始。事实上,把零作为所有数字集合的一个完整成员是一个相对现代的概念,尽管它在数学上是最重要的数字之一。它有许多重要的属性,例如是任意整数的倍数。< br > 一个很好的定理表明,对于任何基数 b,前十亿个正整数都由精确的 n 位数表示(包括前导零)。当且仅当计数从零开始(因此,0到 bn-1) ,而不是从1开始(从1到 bn)时,这种情况才是正确的。这个定理是计算机内存修饰的基础。通常,2n 个单元通过 N 位寻址方案寻址。从一而不是零开始的计数将导致丢失一个内存单元或另一个地址行。由于这两种价格都过于昂贵,计算机工程师们同意使用从零开始的数学符号。好样的!这可能就是为什么所有的内存都从地址 -0开始,即使是那些从 B1开始计数的系统。1401年的设计者们可能为拥有 -0地址而感到羞愧。他们对用户隐藏了它,并假装内存从地址 -1开始。通信工程师,像大多数人一样,从一开始数。例如,他们永远不必承受失去记忆细胞的痛苦。因此,他们很乐意数到1到8,而不是像电脑人那样数到0到7。< sup > < a href = “ https://i.stack.imgur.com/RTs1Q.png”rel = “ nofollow norefrer”> ref

数组名是指向基地址的常量指针。使用 arr [ i ]时,编译器将其操作为 * (arr + i)。因为 int range 是 -128到127,所以编译器认为 -128到 -1是负数,0到128是正数。

对于从零开始的编号,我读过的最优雅的解释是,值并不存储在数字行上的标记位置,而是存储在它们之间的空格中。第一项存储在0和1之间,第二项存储在1和2之间,等等。第 N 项存储在 N-1和 N 之间。可以使用两边的数字来描述项目的范围。按照惯例,单个项目使用下面的数字进行描述。如果给出一个范围(X,Y) ,用下面的数字标识单个数字意味着一个人可以不用任何算术就能识别第一个项目(X 项目) ,但是必须从 Y 中减去一个才能识别最后一个项目(Y-1)。使用上面的数字识别项目可以更容易地识别范围内的最后一个项目(它将是项目 Y) ,但更难识别第一个项目(X + 1)。

虽然根据上面的数字来识别项目并不可怕,但是将范围内的第一个项目(X,Y)定义为 X 上面的项目通常比将它定义为下面的项目(X + 1)更好。

尝试使用基于1的矩阵上的 X,Y 坐标访问像素屏幕。配方非常复杂。为什么复杂?因为最终要把 X,Y 坐标转换成一个数字,偏移量。为什么需要将 X、 Y 转换为偏移量?因为这就是计算机内存的组织方式,作为一个连续的内存单元流(数组)。计算机如何处理阵列单元?使用偏移量(来自第一个单元格的位移,从零开始的索引模型)。

因此,在代码中的某个位置,您需要(或编译器需要)将1基公式转换为0基公式,因为计算机就是这样处理内存的。

数组索引总是从零开始。假设基地址是2000。现在是 arr[i] = *(arr+i)。现在 if i= 0,这意味着 *(2000+0)等于基地址或数组中第一个元素的地址。这个索引被视为偏移量,因此默认的索引从零开始。

假设我们想创建一个大小为5的数组

int array[5] = [2,3,5,9,8]

让数组的第一个元素指向位置100

并且让我们考虑索引从1开始而不是从0开始。

现在我们必须借助 index 来找到第一个元素的位置 (记住第一个元素的位置是100)

因为整数的大小是4位的 因此—— > 考虑指数1,情况将是 指数的大小(1) * 整数的大小(4) = 4 所以它给我们展示的实际位置是

100 + 4 = 104

这是不正确的,因为最初的位置是在100。 它应该指向100而不是104 这是不对的

现在假设我们从0开始索引 那么第一个元素的位置应该是索引(0)的大小 * 整数(4)的大小 = 0

因此-> 第一个元素的位置是100 + 0 = 100

这就是元素的实际位置 这就是为什么索引从0开始;

我有 Java 背景。我已经在下面的图表中给出了这个问题的答案,我已经在一张不言而喻的纸上写下了答案

主要步骤:

  1. 创建参考文献
  2. 数组的实例化
  3. 将数据分配到数组

  • 还要注意的是,当数组刚刚被实例化时... . Zero 被分配给 所有的块默认情况下,直到我们为它分配值
  • 数组以零开始,因为第一个地址将指向 参考文献(i: e-X102 + 0 in image)

enter image description here

注意 : 图像中显示的块是内存表示

首先,您需要知道数组在内部被视为指针,因为“ name of array 本身包含 array 的第一个元素的地址”

ex. int arr[2] = {5,4};

考虑数组从地址100开始 因此元素第一个元素位于地址100,第二个元素位于地址104 现在, 考虑一下,如果数组索引从1开始,那么

arr[1]:-

可以像这样写在指针表达式中-

 arr[1] = *(arr + 1 * (size of single element of array));

考虑 int 的大小是4个字节,现在,

arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);

正如我们知道的,数组名包含它的第一个元素的地址,所以 arr = 100 现在,

arr[1] = *(100 + 4);
arr[1] = *(104);

也就是说,

arr[1] = 4;

因为这个表达式,我们无法访问地址100的元素,这是官方的第一个元素,

现在考虑数组索引从0开始,所以

arr[0]:-

这个问题会以

arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);

现在,我们知道数组名包含它的第一个元素的地址 所以,

arr[0] = *(100);

给出正确的结果

arr[0] = 5;

因此数组索引总是从 c 中的0开始。

参考文献: 所有细节都写在 Brian Kerninghan 和 Dennis Ritchie 的《 C 编程语言》一书中

在数组中,索引表示与起始元素的距离。因此,第一个元素与起始元素的距离为0。这就是为什么数组从0开始。

这是因为 address必须指向数组中的右 element。让我们假设下面的数组:

let arr = [10, 20, 40, 60];

现在让我们考虑地址的起点是 12,而 element的大小是 4 bytes

address of arr[0] = 12 + (0 * 4) => 12
address of arr[1] = 12 + (1 * 4) => 16
address of arr[2] = 12 + (2 * 4) => 20
address of arr[3] = 12 + (3 * 4) => 24

如果它是 没有 zero-based,从技术上讲,我们在 array中的第一个元素地址将是 16,这是错误的,因为它的位置是 12