int* x[n][m]和int (*x) [n][m]之间有什么区别?

13
据我所见,int *x[n][m]声明了一个指向整数的指针的2维数组x,因此分配内存应该像x[i][j] = new int一样容易,并且预期它能正常工作。现在,如果我将声明更改为:

int (*x)[n][m]

x[i][j] = new int不再有效并导致编译错误。

x = (int(*)[n][m]) malloc (sizeof(int[n][m]))然而可以编译通过。从我运行的少量测试中看来,在内存分配后,不同的声明/分配组合似乎不影响变量中存储的值。我是否漏掉了什么?所以我的问题是:int *x[n][m]int (*x)[m][n]之间有什么区别?int (x)[n][m]如何在内存中存储?


1
int (*x)[n][m] 是一个指向整数的二维数组的指针。与指向该数组第一行的指针相比,它们之间的区别微妙且可能令人困惑;我现在没有精力去深入讨论,因为我熬夜得太晚了。 - user2357112
1
你应该知道,在C和C++中,括号的作用往往比人类语言中更为重要。 - Wolf
1
声明x为指向整型数组的数组的指针。 - Radiodef
1
总是有效 <3:http://c-faq.com/decl/spiral.anderson.html,因此第一个意味着“x是指向n个指针数组m的数组”,第二个意味着“x是指向n个数组m的整数数组的指针”。 - Hayri Uğur Koltuk
3个回答

21

int *a[n][m]是指向int类型的指针的二维数组。

int (*p)[n][m]是指向int类型的二维数组的指针 (它是通过对int[n][m]取地址得到的类型)。

在这两种情况下,nm需要是编译时常量,否则在C++中声明将无效(但在C中是有效的)。不过你的编译器可能会有扩展功能来允许此类声明。

第一种情况可以用来模拟三维数组。我说模拟,因为它不是一个正常的具有连续储存空间的数组,并且首先不同的类型。在a的每个元素中,都可以存储整数数组的第一个元素的地址。每个数组的大小可以不同并通过动态分配进行分配。你也可以存储单个(可能在堆栈上分配)整数的指针。

int i = 0;
int a1[2] = {};

int* a2[2][2];
a2[0][0] = a1;  // array to pointer decay here
a2[0][1] = new int[42];
a2[1][0] = new int[84];
a2[1][1] = &i;

p可以指向一个二维数组或多个该类型的数组:

int arr[2][3];
int (*p1)[2][3] = &arr;  // arr decays to int(*)[3], so we need to take the address
int (*p2)[2][3] = new int[42][2][3]; // allocate 42 arrays dynamically

2
正如您在代码中正确指出的那样,“int [n] [m]”不会衰变为“int () [n] [m]”,而是会衰变为“int () [m]”。 “int [o] [n] [m]”将衰变为“int (*) [n] [m]”(数组衰变为其第一个元素的指针,而不是数组本身)。 - sepp2k
@sepp2k 不好意思,谢谢你指出来。我当时在想什么呢。 - jrok

4

正如你可以轻松发现的:

  • int *x[n][m] 是一个指向 int 的二维指针数组。
  • int (*x)[n][m] 是一个指向 int 的二维数组的指针。

回答你的问题,第一个是一个数组,所以内存是“内联”的——它可能是静态的、自动的(在堆栈上)或在堆上,这取决于你在哪里定义它。

第二个是一个指向数组的指针,必须在使用其指向的内容之前初始化指针。最有可能的情况是内存将在堆上分配,但也有可能是在其他地方定义的静态或自动数组。如果在初始化指针之前访问数组成员,则会出现未定义行为。


在这两种情况下都没有“堆分配”的要求,例如 int a[5][3]; int (*x)[5][3] = &a;,甚至是 int a[10][5][3]; int (*x)[5][3] = a; - M.M
第一种情况,当然不是。第二种情况,糟糕。请查看编辑。 - david.pfx

1

解码C声明名称的好网站。以您的示例为例(并替换n=1m=2),我们可以看到:

int *x[1][2]

翻译为:

声明 x 为一个包含两个指向整数的数组的数组

int (*x)[1][2]

声明x为指向int类型的二维数组的指针。

下降的票数是因为你原始的回答只有一个链接,这在这个网站上并不受欢迎。我的编辑展示了一个更好的回答应该是什么样子。 - Duncan Jones
@Duncan 感谢您的解释。这个问题在SOF的使用条款中有描述吗? - αλεχολυτ
1
请参考 http://stackoverflow.com/help/how-to-answer,特别是 为链接提供上下文。另请参考 http://meta.stackexchange.com/q/8259。 - Duncan Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接