我正在尝试以下代码
#include<stdio.h>
int main()
{
int A[3][4] = {{1,2,3,4},{5,6,7,8,},{9,10,11,12}};
int **t = &A[0]; //I do this or **t = A,I guess both are equivalent
printf("%d %p\n\n",*t,A[0]);
return 0;
}
我期望发生的事情:
现在t是一个2d指针(指向指针的指针),它保存A [0]的地址,后者又保存A [0] [0]的地址。所以* t应该给我A [0]的值,即A [0] [0]的地址,** t应该给我A [0] [0]的值,在这种情况下是1
我得到了什么:
* t给出了值1.并且试图找到** t是不可能的,因为它导致了分段错误。
任何人都可以告诉为什么会这样吗?
我尝试了以下解释,但不确定这是否是“正确”的解释。 t保存A [0]的地址,但由于A是一个数组而A [0]是一个数组指针(“不完全”是一个指针),C不为指针A或A [0]分配内存。特别是UNLIKE其他指针变量。它仅为整个数组分配内存。所以A [0]和A [0]的地址(A [0] [0]的地址)基本相同,都属于同一屋檐,不像“独立”实体。结果,t依次间接保持A [0] [0]的地址,* t给出A [0] [0]的值,即1。
以上解释是否正确?看起来很奇怪。
答案 0 :(得分:2)
数组不是指针。
嗯,甚至更多......
多维数组不是双重,三重等指针。
所以你所拥有的只是错误,你的程序会多次调用未定义的行为,而且你无法预料到什么。
鉴于数组在内存中是连续的,你可以像这样重写你的例子:
int A[3][4] = {{1,2,3,4},{5,6,7,8,},{9,10,11,12}};
int *p = &A[0][0];
printf("%d %d %p\n", A[0][0], *p, (void *)p);
答案 1 :(得分:0)
我尝试了以下解释,但不确定这是否是“正确”的解释。
不完全,但有点接近。
t
保存A[0]
的地址,但由于A
是数组而A[0]
是数组指针
A[0]
是数组,具体来说,其类型为int[4]
。
(这不是一个指针),C不为指针
A
或A[0]
特别是UNLIKE其他指针变量分配内存。
数组和指针基本上是不同类型的实体。不要混淆他们。
事实上,在大多数情况下,类型array of T
的表达式被转换为类型pointer to T
的值(指向数组的第一个元素)肯定会导致混淆,但是一定不能忘记这是一个转换。特别是,对于高维数组或数组数组,数组的元素类型本身就是一个数组类型,因此转换的结果是指向数组的指针。
它仅为整个数组分配内存。因此,
A[0]
和A[0]
的地址(A[0][0]
的地址)基本相同,
不,它们本质上是不同的,一个 - A[0]
- 是一个数组,int[4]
,另一个 - &A[0]
- 是一个指向四个int
数组的指针,int(*)[4]
。两者都不是&A[0][0]
。
但是当A[0]
转换为指向其第一个元素&A[0][0]
的指针时,结果地址通常与A[0]
的地址相同(通常是指向对象的指针)保存属于该对象的最低地址的字节的地址,并且A[0]
属于对象A
的(是其一部分),具有最低地址的那个,第一个字节是部分A[0]
的第一个字节是A
)的一部分。
所以&A[0]
和&A[0][0]
通常具有相同的表示形式,但其中一个是int(*)[4]
,另一个是int*
。
属于同一屋檐,不像“独立”实体。因此,
t
反过来间接保留A[0][0]
的地址,*t
提供A[0][0]
的值,即{1}。
除了导致解除引用t
未定义行为的类型不匹配之外,该部分或多或少是正确的。形式上,未定义的行为允许任何事情发生。
实际上,如果sizeof(int) == sizeof(int*)
,解除引用t
会将int
1 A[0][0]
解释为地址,并将其打印为int
(还有另一种未定义的行为),你会得到1
。如果sizeof(int*) == 2*sizeof(int)
在64位系统上很常见,则取消引用t
通常会将两个int
s A[0][0]
和A[0][1]
一起解释为地址 - { {1}}或0x200000001
可能取决于字节顺序。