我认为其他答案遗漏了一些内容。
是的, p[i]
根据定义,等价于 *(p+i)
,因为加法是可交换的,所以等价于 *(i+p)
,而(同样,根据运算符的定义 []
)等价于 i[p]
.
(并且在中 array[i]
,数组名称被隐式转换为指向数组第一个元素的指针。)
但在这种情况下,加法的交换性并不是那么明显。
当两个操作数属于同一类型,或者甚至是提升为通用类型的不同数字类型时,交换性就完全有意义了: x + y == y + x
.
但在这种情况下,我们专门讨论指针运算,其中一个操作数是指针,另一个是整数。(整数 + 整数是不同的运算,指针 + 指针是无意义的。)
C 标准对该 +
运算符的描述( N1570 6.5.6)如下:
对于加法,两个操作数都必须具有算术类型,或者一个操作数必须是指向完整对象类型的指针,而另一个操作数必须是整数类型。
它也同样可以这么说:
对于加法,两个操作数都必须具有算术类型,或者 左 操作数必须是指向完整对象类型的指针,而 右操作数 必须是整数类型。
在这种情况下和 i + p
都是 i[p]
非法的。
用 C++ 术语来说,我们实际上有两组重载 +
运算符,可以大致描述为:
pointer operator+(pointer p, integer i);
和
pointer operator+(integer i, pointer p);
其中只有第一个是真正必要的。
那么为什么会这样呢?
C++ 从 C 继承了这个定义,而 C 又从 B 中得到这个定义(数组索引的交换性在 1972 年的《 B 用户参考》 中得到 BCPL 这个定义,而 BCPL 很可能从更早的语言(CPL?Algol?)中得到这个定义。
因此,数组索引是根据加法来定义的,并且加法(即使是指针和整数)也是可交换的,这种想法可以追溯到几十年前,即 C 的祖先语言。
这些语言的类型远不如现代 C 语言强。特别是,指针和整数之间的区别经常被忽略。(在将关键字 unsigned
添加到语言之前,早期的 C 程序员有时将指针用作无符号整数。)因此,由于操作数的类型不同而使加法不可交换的想法可能不会出现在这些语言的设计者身上。如果用户想要将两个“东西”相加,无论这些“东西”是整数、指针还是其他东西,语言都无权阻止它。
多年来,对该规则的任何改变都会破坏现有代码(尽管 1989 年 ANSI C 标准可能是一个很好的机会)。
改变 C 和/或 C++ 以要求将指针放在左边,将整数放在右边可能会破坏一些现有代码,但不会有真正的表达能力的损失。
因此,现在我们有了 arr[3]
和, 3[arr]
它们的含义完全相同,尽管后者的形式不应该出现在 之外 IOCCC .