正如Joel在Stack Overflow播客#34中指出的,在C编程语言(又名:K&R)中,提到了C:a[5]==5[a]中数组的这个属性
乔尔说这是因为指针运算,但我仍然不明白。为什么a[5]==5[a]?
正如Joel在Stack Overflow播客#34中指出的,在C编程语言(又名:K&R)中,提到了C:a[5]==5[a]中数组的这个属性
乔尔说这是因为指针运算,但我仍然不明白。为什么a[5]==5[a]?
当前回答
关于Dinah的sizeof问题,似乎没有人提到过一件事:
只能向指针添加整数,不能将两个指针相加。这样,当将指针添加到整数或将整数添加到指针时,编译器总是知道需要考虑哪个位的大小。
其他回答
因为避免混淆嵌套非常有用。
你愿意读这个吗
array[array[head].next].prev
或者:
head[array].next[array].prev
顺便说一下,C++对于函数调用具有类似的交换性质。您可以使用成员函数来编写x.f().g(),而不是像在C中那样编写g(f(x))。用查找表替换f和g,您可以编写g[f[x]](函数样式)或(x[f])[g](oop样式)。后者非常适合包含索引的结构:x[xs].y[ys].z[zs]。使用更常见的符号zs[ys[xs[x].y].z]。
我认为其他答案遗漏了一些东西。
是的,p[i]根据定义等价于*(p+i),*(i+p)(因为加法是可交换的)等效于*(i+p),而*(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);
and
pointer operator+(integer i, pointer p);
其中只有第一个是真正必要的。
那么为什么会这样呢?
C++继承了C的这一定义,后者从B获得了它(数组索引的交换性在1972年的《用户参考B》中明确提到),后者从BCPL(1967年的手册)获得了它,BCPL很可能是从更早的语言(CPL?Algol?)获得的。
因此,数组索引是用加法来定义的,即使是指针和整数的加法,也是可交换的,这一想法可以追溯到几十年前,直到C的祖先语言。
这些语言比现代C语言的强类型少得多。特别是,指针和整数之间的区别经常被忽略。(在无符号关键字被添加到语言中之前,早期的C程序员有时将指针用作无符号整数。)因此,由于操作数的类型不同,所以使加法不可交换的想法可能不会出现在这些语言的设计者身上。如果用户想添加两个“东西”,无论这些“东西”是整数、指针还是其他东西,都不能由语言来阻止。
多年来,对该规则的任何修改都会破坏现有的代码(尽管1989年的ANSI C标准可能是一个很好的机会)。
更改C和/或C++以要求将指针放在左边,将整数放在右边,这可能会破坏一些现有代码,但不会损失真正的表达能力。
所以现在我们有了arr[3]和3[arr],意思完全相同,尽管后一种形式不应该出现在IOCCC之外。
关于Dinah的sizeof问题,似乎没有人提到过一件事:
只能向指针添加整数,不能将两个指针相加。这样,当将指针添加到整数或将整数添加到指针时,编译器总是知道需要考虑哪个位的大小。
它在C语言中的指针和阵列教程中有很好的解释由Ted Jensen撰写。
Ted Jensen解释为:
事实上,这是真的,也就是说,无论你在哪里写一个替换为*(a+i)而没有任何问题。事实上,编译器将在任何情况下创建相同的代码。因此,我们看到了指针算术与数组索引相同。任一语法都会产生同样的结果。这并不是说指针和数组是一样的东西,它们不是。我们这么说只是为了确定对于数组的给定元素,我们可以选择两种语法,一种使用数组索引,另一种使用指针算法产生相同的结果。现在,看看最后一个表达式的一部分..(a+i)是使用+运算符和C的规则声明这样的表达式是交换的。即(a+i)与(i+a)相同。因此,我们可以写*(i+a)和*(a+i)一样容易。但*(i+a)可能来自i[a]!所有这些都带来了好奇如果:字符a[20];写a[3]=“x”;与写作相同3[a]=“x”;
很好的问题/答案。
我只想指出,C指针和数组并不相同,尽管在这种情况下,差异并不是本质的。
考虑以下声明:
int a[10];
int* p = a;
在a.out中,符号a位于数组开始的地址,符号p位于存储指针的地址,指针在该内存位置的值是数组的开始。