正如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]?
当前回答
C基于BCPL。BCPL将存储器直接暴露为一系列可寻址字。一元运算符!X(也称为LV)为您提供了地址位置X的内容。为了方便起见,还有一个二进制运算符X!Y等于!(X+Y),它为您提供了位置X处数组的第Y个字的内容,或者等效地,位置Y处数组的X个字。
在C,X!Y变成了X[Y],但是!的原始BCPL语义!(X+Y)表示通过,这解释了为什么算子是可交换的。
其他回答
我只是发现这种丑陋的语法可能是“有用的”,或者至少当你想处理一个索引数组,这些索引引用了同一个数组中的位置时,使用起来非常有趣。它可以替换嵌套的方括号,使代码更可读!
int a[] = { 2 , 3 , 3 , 2 , 4 };
int s = sizeof a / sizeof *a; // s == 5
for(int i = 0 ; i < s ; ++i) {
cout << a[a[a[i]]] << endl;
// ... is equivalent to ...
cout << i[a][a][a] << endl; // but I prefer this one, it's easier to increase the level of indirection (without loop)
}
当然,我很确定在实际代码中没有这样的用例,但我还是觉得很有趣:)
C基于BCPL。BCPL将存储器直接暴露为一系列可寻址字。一元运算符!X(也称为LV)为您提供了地址位置X的内容。为了方便起见,还有一个二进制运算符X!Y等于!(X+Y),它为您提供了位置X处数组的第Y个字的内容,或者等效地,位置Y处数组的X个字。
在C,X!Y变成了X[Y],但是!的原始BCPL语义!(X+Y)表示通过,这解释了为什么算子是可交换的。
我知道问题得到了答案,但我忍不住分享了这个解释。
我记得编译器设计原理,假设a是一个int数组,int的大小为2字节,&a的基址为1000。
[5]将如何工作->
Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010
So,
类似地,当c码被分解为3地址码时,5[a]将变为->
Base Address of your Array a + (size of(data type for array a)*5)
i.e. 1000 + (2*5) = 1010
所以基本上这两个语句都指向内存中的相同位置,因此a[5]=5[a]。
这一解释也是数组中负索引在C中工作的原因。
即,如果我访问[-5],它会给我
Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990
它将在990位置返回我的对象。
很好的问题/答案。
我只想指出,C指针和数组并不相同,尽管在这种情况下,差异并不是本质的。
考虑以下声明:
int a[10];
int* p = a;
在a.out中,符号a位于数组开始的地址,符号p位于存储指针的地址,指针在该内存位置的值是数组的开始。
不是答案,只是一些思考的食物。如果类具有重载的索引/下标运算符,则表达式0[x]将不起作用:
class Sub
{
public:
int operator [](size_t nIndex)
{
return 0;
}
};
int main()
{
Sub s;
s[0];
0[s]; // ERROR
}
由于我们无法访问int类,因此无法执行此操作:
class int
{
int operator[](const Sub&);
};