c - 这些 C 函数参数类型有什么区别?

标签 c gcc ansi-c

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;
}

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

最佳答案

首先,让我们理清哪些声明实际上是等效的,因为示例代码中有很多冗余。

例如,这三个声明对编译器来说意味着完全相同的事情:

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

任何数组类型的函数参数都会衰减为指向数组第一个元素的指针,因此 int **a 是实际用于所有三个函数参数的类型。

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

void j(int (*a)[3]) {}
void k(int a[][3]) {}

这里,参数的有效类型是int (*a)[3]

<小时/>

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

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

第一个是指向 int 指针的指针。这通常用于将 2D 数组作为指针传递给指向行数组的指针数组。索引工作正常,但需要正确设置额外的指针数组。

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

最后一个传递一个宽度为三个 int 的二维数组。您可以使用 a[y][x] 轻松对其进行索引,因为当您说 a[y] 时,编译器知道这些行是三个整数的数组,并且将相应地计算偏移量。

关于c - 这些 C 函数参数类型有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43590226/

相关文章:

C++ 编译器标志忽略外部库的警告但不包含目录

c++ - 在类模板中定义变量模板

c - 如何阻止 VS2010 自动包含 Ansi C 项目的文件

c - 解码后的shellcode不执行: Illegal instruction: 4

c - 使用 libconfig 读取 C 中的配置文件

c - Timer a在msp430中高级编译优化模式下的使用

c++ - linux上g++9.3.0 -O2的一个奇怪bug

c - Malloc() 和 free() 阻止我在 C 中按值传递结构

c - 如何停止用替换字符 � 替换字符?

c - 访问 char 数组中结构的空指针