以下C代码段,
int a[2][3][2] = { { {1,2},{3,4},{5,6} },{{7,8},{9,10},{11,12} } };
printf("%d %d",a[1]-a[0],a[1][0]-a[0][0]);
此代码提供输出3 6
,但我没有得到这个。
我可以将3D数组a[2][3][2]
可视化为两个大小为3x2的2D
数组,其索引如下:
a[0][0]--> | 1 2 || 7 8 | <--a[1][0]
a[0|[1]--> | 3 4 || 9 10|
| 5 6 || 11 12|
a[0] a[1]
假设a[0]
的地址为1000
,a[1]
的地址为1012
,假设int
的大小为2个字节。
所以(a[1] - a[0])
应该是12,但它给出的3. 3实际上是矩阵中的行数。但是,要获得行数,代码应该是这样的:
(a[1] -a[0])/(row_size *sizeof(int));
同样,在a[1][0]-a[0][0]
。
我不明白这件事。 请解释。 谢谢。
答案 0 :(得分:9)
让我们尝试写出数组在内存中的样子:
+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+ | a[0][0][0] | a[0][0][1] | a[0][1][0] | a[0][1][1] | a[0][2][0] | a[0][2][1] | a[1][0][0] | a[1][0][1] | a[1][1][0] | a[1][1][1] | a[1][2][0] | a[1][2][1] | +------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+ ^ ^ ^ ^ | | | | a[0][0] a[0][1] a[0][2] a[1][0] | | a[0] a[1]
当你这样做的时候a[1] - a[0]
你让子数组衰减为指针到它们的第一个元素,两个指针之间的差异以它们的解引用类型为单位。
因此,对于a[0]
(和a[1]
),类型为int [3][2]
。它衰减到指向其第一个元素的指针,该元素的类型为int (*)[2]
。解除引用的指针将是int [2]
类型。现在int [2]
和a[0]
之间有多少a[1]
?有三个这样的元素,因此a[1] - a[0]
的结果是3
。
如果我们选择a[1][0] - a[0][0]
,则a[1][0]
和a[0][0]
的类型均为int [2]
。它衰减为int *
类型的指针,解除引用的类型为int
。 int
和a[0][0]
之间有六个a[1][0]
元素。
答案 1 :(得分:2)
根据standard 6.5.6p9,这是未定义的行为:
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素; 结果是两个数组的下标的差异元素。结果的大小是实现定义的,它的类型(有符号整数类型)是在头文件中定义的ptrdiff_t ...
问题是它会在大多数系统中产生预期的效果。但请注意a[0]
和a[1]
属于同一个数组a
。但是a[0][0]
和a[1][0]
属于不同的数组对象,然后指针将指向违反上述规则的两个不同的数组对象。这就是未定义行为的原因。