7

(自我回答的问答——这件事不断出现)

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

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

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

但是通过 C 标准,我发现没有什么叫做“数组样式索引”。事实上,运算符[]并不期望任何一个操作数是一个数组,而是一个指针或一个整数!

6.5.2.1 数组下标

约束

其中一个表达式应具有类型''指向完整对象类型的指针'',另一个表达式应具有整数类型,并且结果具有类型''<em>type''。

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

4

1 回答 1

12

出于可读性的原因,您确实应该使用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). wherearr仍然是指向第一个元素的指针。

这就是为什么您引用的描述告诉您任何一个操作数都可以是指针而另一个是整数的原因。*(arr+i)因为很明显,如果我们键入或*(i+arr)- 那是等效的代码并不重要 。

这反过来又允许我们编写混淆的“笑话”代码,例如i[arr],它实际上是有效的 C 并且完全等同于arr[i]. 但是不要在实际应用程序中编写这样的代码。

于 2019-04-18T14:08:41.893 回答