我创建了一个2D数组,并尝试打印某些值,如下所示:
int a[2][2] = { {1, 2},
{3, 4}};
printf("%d %d\n", *(a+1)[0], ((int *)a+1)[0]);
输出结果为:
3 2
我理解为什么3
是第一个输出(a+1
指向第二行,我们打印其0th
元素。
我的问题是关于第二个输出,即2
。我的猜测是,由于将a
类型转换为int *
,2D数组被视为一维数组,因此a+1
充当2nd
元素的指针,因此我们得到的输出为2
。
我的假设是否正确或背后是否有其他逻辑?
另外,最初将a
视为指针int (*)[2]
或int **
时的类型是什么?
答案 0 :(得分:10)
当你写表达式
时(int *)a
然后逻辑上原始数组可以通过以下方式被视为一维数组
int a[4] = { 1, 2, 3, 4 };
因此表达式a
指向第一个元素,该元素等于这个虚构数组的1。表达式( a + 1 )
指向虚数组的第二个元素等于2,而表达式( a + 1 )[0]
返回对此元素的引用,即得到2。
答案 1 :(得分:9)
我的假设是正确的还是还有其他一些逻辑?
是。
*(a+1)[0]
相当于a[1][0]
((int *)a+1)[0]
相当于a[0][1]
。
说明:
a
衰减指向2D数组的第一个元素,即指向第一行。 *a
取消引用该行,即2 int
的数组。因此*a
可以被视为第一行的数组名称,它进一步衰减到指向其第一个元素的指针,即1
。 *a + 1
将指向第二个元素。取消引用*a + 1
将提供1
。所以:
((int *)a+1)[0] == *( ((int *)a+1 )+ 0)
== *( ((int *)a + 0) + 1)
== a[0][1]
请注意,a
,*a
,&a
,&a[0]
和&a[0][0]
都具有相同的地址值,尽管它们的类型不同。衰减后,a
的类型为int (*)[2]
。将其转换为int *
只会使地址值输入int *
,算术(int *)a+1
会提供第二个元素的地址。
另外,最初被视为指针
(int (*)[2]
或int **
时的类型是什么?
它成为指向2 int
数组的指针,即int (*)[2]
答案 2 :(得分:3)
2D数组本质上是一个具有一些额外编译器知识的单维数组。
当您将a
转换为int*
时,您会删除此知识,并将其视为普通的一维数组(在您的情况下,它会在内存中查找1 2 3 4
)。< / p>
答案 3 :(得分:0)
这里要认识到的关键是a
保存第一行所在地址的值。由于整个数组从相同的位置开始,整个数组也具有相同的地址值;对于第一个元素也一样。
以C
条款:
&a == &a[0];
&a == &a[0][0];
&a[0] == &a[0][0];
// all of these hold true, evaluate into 1
// cast them if you want, looks ugly, but whatever...
&a == (int (*)[2][2]) &a[0];
&a == (int (*)[2][2]) &a[0][0];
&a[0] == (int (*)[2]) &a[0][0];
出于这个原因,当你将a
转换为int *
时,它只是通过类型和值变为与&a[0][0]
相当的1对1。如果您要将这些操作应用于&a[0][0]
:
(&a[0][0] + 1)[0];
(a[0] + 1)[0];
*(a[0] + 1);
a[0][1];
对于被视为指针的a
类型,虽然我不确定,但应该是int (*)[2]
。