一些上下文:
首先,请记住,当类型为“N-element array of T
”的表达式出现在它不是sizeof
一元运算符的操作数的上下文中&
,或者不是用于初始化另一个数组的字符串时声明时,它将被转换为“指针T
”类型的表达式,其值将是数组中第一个元素的地址。
这意味着当您将数组参数传递给函数时,该函数将接收一个指针值作为参数;在调用函数之前,数组表达式被转换为指针类型。
这一切都很好,但是为什么arr[]
允许作为指针声明呢?我不能说这是肯定的原因,但我怀疑这是 B 语言的遗留物,C 是从 B 语言衍生而来的。事实上,几乎所有关于 C 中数组的奇怪或不直观的东西都是 B 的保留。
B 是一种“无类型”语言;对于浮点数、整数、文本等,您没有不同的类型。一切都存储为固定大小的单词或“单元”,而内存被视为单元的线性阵列。当您在 B 中声明一个数组时,如
auto arr[10];
编译器将为数组留出 10 个单元格,然后留出额外的第 11 个单元格来存储数组第一个元素的偏移量,并且该额外的单元格将绑定到变量arr
. 与 C 中一样,B 中的数组索引计算为*(arr + i)
; 您将获取存储在 中的值arr
,添加偏移量i
,然后取消引用结果。Ritchie 保留了大部分这些语义,除了不再为指向数组第一个元素的指针留出存储空间。相反,该指针值将在翻译代码时从数组表达式本身计算出来。这就是为什么数组表达式被转换为指针类型的原因,为什么&arr
和arr
给出相同的值,如果不同的类型(数组的地址和数组的第一个元素的地址相同)以及为什么数组表达式不能成为赋值的目标(没有什么可以赋值;没有存储有为独立于数组元素的变量预留)。
现在这是有趣的一点;在 B 中,您将“指针”声明为
auto ptr[];
这具有分配单元格以将偏移量存储到数组的第一个元素并将其绑定到的效果ptr
,但ptr
没有特别指向任何地方;您可以将其分配为指向不同的位置。我怀疑符号被搁置有几个原因:
- 大多数开发 C 初始版本的人都熟悉它。
- 它有点强调参数代表调用者中的一个数组;
就个人而言,我更希望 Ritchie 曾经*
在任何地方指定指针,但他没有(或者,或者,[]
在所有上下文中都使用指定指针,而不仅仅是函数参数声明)。我通常会建议大家*
对函数参数使用符号而不是[]
,只是因为它更准确地传达了参数的类型,但我可以理解为什么人们更喜欢第二种符号。