指针是否支持“数组样式索引”?

Lun*_*din 5 c arrays pointer-arithmetic subscript-operator array-indexing

(常见问题解答-此问题不断出现)

我假设读者知道指针算法是如何工作的。

int arr[3] = {1,2,3};
int* ptr = arr;
...
*(ptr + i) = value;
Run Code Online (Sandbox Code Playgroud)

老师/ C书籍不断告诉我,我不应该*(ptr + i)像上面的示例那样使用,因为“指针支持数组样式索引”,而我应该使用它ptr[i] = value;。那里没有论据-更容易阅读。

但是从C标准来看,我什么都没有找到,叫做“数组样式索引”。实际上,运算符[]并不期望任何一个操作数都是数组,而是指针或整数!

6.5.2.1数组下标

约束条件

其中一个表达式的类型应为“完成对象类型的指针”,另一个表达式的类型应为整数,结果的类型应为“ type ”。

为什么数组下标运算符不期望数组?标准错了吗?我的老师/ C书困惑了吗?

Lun*_*din 7

出于可读性原因,您确实应该使用ptr[i]over *(ptr + i)。但是除此之外[],严格来说,运算符实际上从未与数组操作数一起使用。

数组在表达式中使用时,总是“衰减”到指向第一个元素的指针中(有些例外)。C17 6.3.2.1/3,重点是:

除非它是sizeof运算符的操作数或一元&运算符,或者是用于初始化数组的字符串文字,否则类型为“ array of type”的表达式将转换为类型为“ pointer”的表达式键入'',它指向数组对象的初始元素,不是左值。

这意味着,无论何时键入arr[i],操作数arr都会被指向该数组内第一个元素的指针替换。这非正式地称为“阵列衰减”。更多信息在这里:什么是阵列衰减?

因此,无论何时使用[]运算符,都可以在指针上使用它。总是。

C标准说,保证该运算符等效于指针算术(C17 6.5.2.1/2):

下标操作符的定义[]E1[E2]相同(*((E1)+(E2)))

因此,无论何时键入arr[i],它实际上都会被静默替换*(arr+i)。哪里arr仍然是第一个元素的指针。

这就是为什么您引用的描述告诉您一个操作数可以是指针而另一个是整数的原因。因为显然我们键入*(arr+i)*(i+arr)- 没关系 ,这就是等效的代码。

这反过来又使我们能够编写模糊的“笑话”代码,例如i[arr],它实际上是有效的C,并且完全等效于arr[i]。但是不要在实际的应用程序中编写此类代码。

  • 数十年来被要求编写“ offset(register)”的汇编语言程序员可能会因为编写“ i [array]”而被宽恕。 (2认同)