“那么 2D int 数组名称的值是多少?”
“我其实明白数组不是指针。在我的问题中,
我的实际意思是当数组的名称用于
表达式,编译器会生成指针常量。”
你必须在这里小心。作为您在问题下方评论的后续内容,数组/指针转换规则如何应用影响转换产生的type 存在细微差别。这将决定您是否以及如何在表达式中使用数组名称。
"...编译器会生成指针常量。"
否。编译器不生成指针常量,编译器遵循C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)。当在表达式中使用数组名称时,表达式会使用数组转换为指针所产生的地址进行计算(受第 3 段中所述的 4 个例外的影响)。
关于数组/指针转换的规则不依赖于维数,无论如何该规则都适用。 然而,转换产生的指针的type 确实取决于数组维数。这很关键,这将决定您对数组名称的使用是否有效。
帮助巩固转化过程中发生的事情的一种方法是逐步进行。从一维数组开始,然后逐步向上。
6.3.2.1 - 访问时将一维数组转换为指针
当你有一个简单的数组时,例如
int array[10];
在访问数组时,转换为指向第一个元素的指针,例如,地址元素&array[0]。 (这只是一个指向 int 的指针,或者具有正式类型int *)
6.3.2.1 - 访问时将二维数组转换为指针
对于 2D 数组,规则同样适用,例如
int array[10][10];
这里的array,一个二维数组,本质上是一个包含 10 个 - int[10] 数组(一维数组的数组)的数组。在访问时array[10][10] 以完全相同的方式转换为指向10-int 的第一个数组的指针&array[0][0](这导致指向int[10] 的数组的指针或正式type int (*)[10]) 它不是 pointer-to-pointer(例如 int**),它是一个非常具体的指向 int[10] 数组的指针。
(noteint *[10] (an array of 10 pointers 之间的重要区别,它在访问时会变成一个指向指针的指针) 和int (*)[10](一个指针 指向10个数组 int))
回答
“所以...当在表达式中使用时,2D int 数组名称的值” -- 是第一个 1D array 整数的地址使用正式类型int (*)[N](其中N 是每行的元素数)向上扩展二维数组。
标准应用方式的细微差别
类型对于正确使用数组名称至关重要。对于 2D 数组,结果地址是一个指向 array 的指针。如果取消引用该指针会产生什么结果? (答案: 一个 array)当您通过取消引用的指针访问该 array 时会发生什么? (提示:访问规则的转换再次适用)。您必须知道转换后的指针类型是什么,才能在表达式中正确使用数组名称。
一个例子可能会有所帮助
或者它可能不会,但是使用由数组访问和指针转换产生的指针类型可能有助于理解。下面的示例声明了一个简单的4x3 2D 数组int。然后它声明一个适当类型的指针 (p) 以允许在将数组地址分配给指针的表达式中使用数组名称。然后使用数组名初始化的指针进一步初始化指向第一个数组中第一个元素的整数指针 (ip)。
然后该示例输出每个元素的地址,然后使用指针p 输出构成二维数组的每个行数组的开头地址。最后,代码进入验证循环,通过 (1) 数组索引、(2) 使用偏移量的指针 p 保存的地址和 (3) ip 保存的地址来比较每个元素的地址。目的是使用由分配数组名称的表达式产生的每个不同指针,然后引用每个元素并确保每个指针持有的地址一致。
#include <stdio.h>
int main (void) {
int array[ ][3] = { {1, 2, 3}, /* 2D array values */
{3, 4, 5},
{5, 6, 7},
{7, 8, 9} },
(*p)[3] = array, /* pointer to array */
*ip = *p; /* integer poiner */
size_t size = sizeof array,
nele = size / sizeof **array,
nrow = size / sizeof *array,
ncol = sizeof *array / sizeof **array;
printf ("2D array statistics:\n\n"
" size: %zu (bytes)\n nele: %zu (ints)\n"
" nrow: %zu\n ncol: %zu\n",
size, nele, nrow, ncol);
puts ("\naddress of each array element:\n");
for (size_t i = 0; i < nrow; i++) {
for (size_t j = 0; j < ncol; j++)
printf (" %p", (void*)&array[i][j]);
putchar ('\n');
}
puts ("\naddress of each 1D array:\n");
for (size_t i = 0; i < nrow; i++)
printf (" %p\n", (void*)p[i]);
puts ("\nvalidating each array element address by index & pointer:\n");
for (size_t i = 0; i < nrow; i++) {
for (size_t j = 0; j < ncol; j++) {
if (ip != &array[i][j] || ip != *p + j) {
fprintf (stderr, "address validation failed for "
"array[%zu][%zu]\n(%p != %p || %p != %p)\n",
i, j, (void*)ip, (void*)&array[i][j],
(void*)ip, (void*)(p + j));
return 1;
}
ip++;
}
p++;
}
puts (" done!");
return 0;
}
使用/输出示例
$ ./bin/array_2d_access
2D array statistics:
size: 48 (bytes)
nele: 12 (ints)
nrow: 4
ncol: 3
address of each array element:
0x7ffe7c9a9780 0x7ffe7c9a9784 0x7ffe7c9a9788
0x7ffe7c9a978c 0x7ffe7c9a9790 0x7ffe7c9a9794
0x7ffe7c9a9798 0x7ffe7c9a979c 0x7ffe7c9a97a0
0x7ffe7c9a97a4 0x7ffe7c9a97a8 0x7ffe7c9a97ac
address of each 1D array:
0x7ffe7c9a9780
0x7ffe7c9a978c
0x7ffe7c9a9798
0x7ffe7c9a97a4
validating each array element address by index & pointer:
done!
让我知道这是否有帮助以及您是否还有其他问题。