将两个2d指针 - 2d阵列等同起来

时间:2013-04-12 21:00:21

标签: c pointers

我正在尝试以下代码

#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。

以上解释是否正确?看起来很奇怪。

2 个答案:

答案 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不为指针AA[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可能取决于字节顺序。