这些C函数参数类型的区别是什么?

这些C函数参数类型的区别是什么?,c,gcc,ansi-c,C,Gcc,Ansi C,这些C函数参数类型的区别是什么? 指针数组和二维数组之间有很多混淆 注释是GCC警告日志。首先,让我们整理一下哪些声明实际上是等效的,因为示例代码中存在大量冗余 例如,这三个声明对编译器的意义完全相同: void f(int **); void g(int *[]); void h(int *[3]); void i(int (*)[]); void j(int (*)[3]); void k(int [][3]); void f(int **a) {} void g(int *a[]) {}

这些C函数参数类型的区别是什么? 指针数组和二维数组之间有很多混淆
注释是GCC警告日志。

首先,让我们整理一下哪些声明实际上是等效的,因为示例代码中存在大量冗余

例如,这三个声明对编译器的意义完全相同:

void f(int **);
void g(int *[]);
void h(int *[3]);
void i(int (*)[]);
void j(int (*)[3]);
void k(int [][3]);

void f(int **a) {}
void g(int *a[]) {}
void h(int *a[3]) {}
void i(int (*a)[]) {}
void j(int (*a)[3]) {}
void k(int a[][3]) {}

int main(void) {
    int a[3] = {1,2,3};
    int b[2] = {4,5};
    int *c[2] = {a, b};
    int d[2][3] = {{1,2,3},{4,5,6}};
    f(c);
    f(d); // note: expected ‘int **’ but argument is of type ‘int (*)[3]’
    g(c);
    g(d); // note: expected ‘int **’ but argument is of type ‘int (*)[3]’
    h(c);
    h(d); // note: expected ‘int **’ but argument is of type ‘int (*)[3]’
    i(c); // note: expected ‘int (*)[]’ but argument is of type ‘int **’
    i(d);
    j(c); // note: expected ‘int (*)[3]’ but argument is of type ‘int **’
    j(d);
    k(c); // note: expected ‘int (*)[3]’ but argument is of type ‘int **’
    k(d);
    return 0;
}
任何数组类型的函数参数都会衰减为指向数组第一个元素的指针,因此
int**a
是实际用于所有三个函数参数的类型

同样,这两个声明是相同的:

void f(int **a) {}
void g(int *a[]) {}
void h(int *a[3]) {}
这里,参数的有效类型是
int(*a)[3]


这只剩下三种不同的变体:

void j(int (*a)[3]) {}
void k(int a[][3]) {}
第一个是指向
int
的指针。这通常用于将2D数组作为指针传递给线数组的指针数组。索引工作正常,但需要正确设置额外的指针数组

第二个几乎不可用:它定义了一个指向数组的指针,数组的大小未知。因此,不能使用
a[y][x]
索引到数组中,因为行的大小未知,因此无法计算行
y
的偏移量


最后一个通过一个宽度为三
int
s的2D数组。你可以很容易地用
a[y][x]
对它进行索引,因为当你说
a[y]
时,编译器知道行是三个整数的数组,并会相应地计算偏移量。

int**
是指向
int
的指针
int(*)[3]
是指向
int
数组的指针。两者都不同,不能互换。请参阅@WernerHenze的可能重复项。它没有重复,但我没有注意到运算符的优先级,更容易理解这些奇怪的声明。
void f(int **a) {}
void i(int (*a)[]) {}
void j(int (*a)[3]) {}