正如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]?
当前回答
现在有点历史了。在其他语言中,BCPL对C的早期发展产生了相当大的影响。如果您在BCPL中声明的数组类似于:
let V = vec 10
实际上分配了11个字的内存,而不是10个。通常V是第一个,并包含紧接其后的单词的地址。因此,与C不同,命名V到那个位置,并获取数组第0个元素的地址。因此,BCPL中的数组间接寻址表示为
let J = V!5
真的不得不做J=!(V+5)(使用BCPL语法),因为需要获取V以获得阵列的基地址。因此,V!5和5!V是同义词。据坊间观察,WAFL(Warwick Functional Language,沃里克函数语言)是用BCPL编写的,据我所知,在访问用作数据存储的节点时,倾向于使用后一种语法而不是前一种语法。当然这是35到40年前的某个地方,所以我的记忆有点生疏
省去了额外的存储字,并在命名数组时让编译器插入数组的基地址,这一创新是后来才出现的。根据C历史论文,这大约发生在C中添加结构的时候。
注意!BCPL中既有一元前缀运算符,也有二元中缀运算符,在这两种情况下都是间接操作。只是二进制形式在执行间接操作之前包括两个操作数的相加。鉴于BCPL(和B)面向单词的性质,这实际上很有意义。当C获得数据类型时,“指针和整数”的限制就变得必要了,sizeof也成了一件事。
其他回答
对于C中的指针,我们有
a[5] == *(a + 5)
而且
5[a] == *(5 + a)
因此,a[5]==5[a]是正确的。
在c编译器中
a[i]
i[a]
*(a+i)
引用数组中元素的方式不同!(一点都不奇怪)
我只是发现这种丑陋的语法可能是“有用的”,或者至少当你想处理一个索引数组,这些索引引用了同一个数组中的位置时,使用起来非常有趣。它可以替换嵌套的方括号,使代码更可读!
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标准对[]运算符的定义如下:
a[b]==*(a+b)
因此,[5]将评估:
*(a + 5)
并且5[a]将评估:
*(5 + a)
a是指向数组的第一个元素的指针。a[5]是距离a更远的5个元素的值,与*(a+5)相同,从小学数学中我们知道它们是相等的(加法是可交换的)。
不是答案,只是一些思考的食物。如果类具有重载的索引/下标运算符,则表达式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&);
};