0

我正在尝试以下代码

#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 是一个二维指针(指向指针的指针),它保存着 A[0] 的地址,而 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。

上面的解释正确吗?有点奇怪。

4

2 回答 2

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);
于 2013-04-12T21:03:35.917 回答
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]- 是指向四个数组的指针intint(*)[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*),取消引用将1t解释为地址,并且如果您将其打印为(又一个未定义的行为),您将被打印。如果像 64 位系统上常见的那样,解引用通常会将两个s和一起解释为地址 -或者可能取决于字节顺序。intA[0][0]int1sizeof(int*) == 2*sizeof(int)tintA[0][0]A[0][1]0x2000000010x100000002

于 2013-04-12T21:55:31.940 回答