数组不是指针(这一点怎么强调都不过分)。
话虽如此,数组衰减为指向其第一个元素的指针。例如:
int a[10];
int b[20][30];
void print_a(int *);
void print_b(int (*)[30]);
print_a(a);
print_b(b);
a 的第一个元素是a[0],同样b 的第一个元素是b[0]。你基本上把第一个维度拿走了,把它改成(*);稍后我会解释更多,因为它比这更复杂。
指针和数组之间的关系充满了微妙的上下文,这些微妙之处并不难掌握,但不同范围内的大小信息使它变得有趣,也有助于让您了解衰减是如何工作的:
#include <stdio.h>
int h(int *pa)
{
printf("h(int *): sizeof pa=%zu\n", sizeof pa);
printf("h(int *): sizeof *pa=%zu\n", sizeof *pa);
return *pa;
}
int g(int (*pa)[5])
{
printf("g(int (*)[5]): sizeof pa=%zu\n", sizeof pa);
printf("g(int (*)[5]): sizeof *pa=%zu\n", sizeof *pa);
return h(*pa);
}
int f(int (*pa)[3][5])
{
printf("f(int (*)[3][5]): sizeof pa=%zu\n", sizeof pa);
printf("f(int (*)[3][5]): sizeof *pa=%zu\n", sizeof *pa);
return g(*pa);
}
int main(void)
{
int arr[2][3][5] = {{{11235}}};
printf("main: sizeof arr=%zu\n", sizeof arr);
printf("main: sizeof *arr=%zu\n", sizeof *arr);
printf("%d\n", f(arr));
}
每个指针的大小都相同(在所有平台上可能并不总是如此!),但是通过取消引用指针,您可以看到数组中给定元素的大小,无论您是否使用一元 * 运算符取消引用或[N] 数组表示法,根据定义相当于*((array)+(N))。
不管怎样,回到指针和数组的区别,你应该明白int[20][30]和int **是不一样的。这是为什么?由于int[20][30] 衰减为int(*)[30] 类型的指针这一事实,因此在取消引用指针之前不会发生更多衰减。此外,int ** 实际上是int *(*),这意味着它可以指向指针数组的第一个元素。也就是说,int ** 可能曾经是 int *[N]。
int foo[x][y][z] <=> int (*foo)[y][z]
int *foo[m][n] <=> int *(*foo)[n]
int (*foo[a])[b] <=> int (**foo)[b]
在第一种情况下,我们有一个 3-D 数组,它衰减为指向 2-D 数组的指针;换句话说,除了大小问题之外,数组数组和指向数组的指针在许多情况下密切相关并且可以互换。第一个维度x 是衰减的维度,留下y 和z 维度。
在第二种情况下,我们有一个二维指针数组。这衰减为指向指针数组的指针。同样,数组数组与指向数组的指针密切相关,维度m衰减,留下维度n。
在第三种情况下,我们有一个指向数组的指针数组。它衰减为指向数组指针的指针。由于维度a 最接近变量名,即衰减的那个,留下维度b。请注意,由于它是一个指向数组的指针数组,因此指针可以指向数组本身的第一个元素:
int arr[2][3][5];
int (*foo[2])[5] = { arr[0], arr[1] };
int (**foo_ptr)[5] = foo;
回顾:
- 数组(大小 B)的数组(大小 A) 指向数组的指针(大小 B)
- 指针数组(大小 A) 指向指针的指针
- 衰减/增长的数组始终是最内层的数组/指针,最内层是最接近变量声明中的变量名的数组/指针,数组具有比指针更高的关联性,当然圆括号会有所不同。
这个兔子洞显然会让人困惑,但我希望我至少能帮上一点忙!