int a[10][5];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
cout << i[j[a]];
cout << j[i[a]];
}
}
编辑:假设值已经初始化为数组,那么这个 cout 有效吗?
请仅解释该i[j[a]];
部分,而不管我只关心该声明的程序!
int a[10][5];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
cout << i[j[a]];
cout << j[i[a]];
}
}
编辑:假设值已经初始化为数组,那么这个 cout 有效吗?
请仅解释该i[j[a]];
部分,而不管我只关心该声明的程序!
cout << i[j[a]];
cout << j[i[a]];
在 C++ 中,该X[Y]
符号在词法上等价于*(X+Y)
:
[C++11: 5.2.1/1]:
[..]该表达式E1[E2]
(根据定义)与*((E1)+(E2))
[..]
这意味着Y[X]
等价于,*(Y+X)
这与加法是可交换的 相同。*(X+Y)
出于某种原因,作者决定通过编写这个令人困惑的代码来尝试“聪明”。
通过交换律和X[Y]
单独的定义:
i[j[a]] => i[*(j+a)] => *(i+*(j+a)) => *(*(a+j)+i) => *(a[j] + i) => a[j][i]
j[i[a]] => j[*(i+a)] => *(j+*(i+a)) => *(*(a+i)+j) => *(a[i] + j) => a[i][j]
那么,您的cout
陈述相当于:
cout << a[j][i];
cout << a[i][j];
在任何情况下,循环都会尝试读取数组边界,因为数组5
的每个元素中只有整数a
,而您的内部循环会尝试一直到10
.
其实际结果是不确定的,因此您可能会获得无声的成功、无声的失败、任意值、分段错误、断电、黑洞、圣诞节的小马、脚趾截肢或新自行车。
即使循环条件固定,请注意第一个语句在语义上是不正确的(假设您继续将第一个维度归因于外部循环,将第二个维度归因于内部循环)。
C 数组有一个奇怪的怪癖,允许通过“相反”方向访问它们。这深深植根于数组的指针算法。例如,a[1]
等价于*(a + 1)
。同样,1[a]
等价于*(1 + a)
。由于加法的交换性质,这非常有效。更多细节可以在这里找到。
有了这些知识,表达i[j[a]]
可以分为两个不同的部分。由于您拥有的数组的多维性质,j[a]
相当于which 将返回另一个数组,例如,我们将调用此返回的数组。然后你就有了相当于. 将它们重新组合在一起会告诉你这相当于. 实际上,这意味着这只是一种混淆的书写方式。*(j + a)
p
i[p]
*(i + p)
i[j[a]]
*(i + *(j + a))
i[j[a]]
a[j][i]
在 C/C++ 中,可以用整数索引为指针下标,也可以用指针为整数索引下标,含义(语义)完全相同。我不知道为什么疯狂的语法是有效的,但它确实如此,而且显然它会永远存在。
#include <stdio.h>
int main(int argc, char** argv)
{
int i = 1, array[10];
printf("%ld\n", &(i[array])-&(array[i]));
return 0;
}
输出:
0