c - 将数组和矩阵传递给函数作为 C 中的指针和指向指针的指针

标签 c pointers parameters

给定以下代码:

void
foo( int* array ) 
{
    // ...
}

void
bar( int** matrix ) 
{
    // ...
}

int
main( void ) {
    int array[ 10 ];
    int matrix[ 10 ][ 10 ];

    foo( array );
    bar( matrix );

    return 0;
}

我不明白为什么会收到此警告:

warning: passing argument 1 of ‘bar’ from incompatible pointer type

虽然 'foo' 调用似乎没问题。

谢谢:)

最佳答案

嗯,从 SO 的概览中可以看出,C 社区肯定没有很好地理解它。神奇的是,以下所有内容都是完全 100% 等效的:

void foo(int (*array)[10]);
void foo(int array[][10]);
void foo(int array[10][10]);
void foo(int array[42][10]);

区分指针和数组是非常重要的。 数组不是指针。数组可以转换为指向其第一个元素的指针。如果你有一个指针,你有这个:

--------
| ptr  |  -------> data
--------

但是,如果你有一个数组,你有这个:

---------------------------
| c1 | c2 | c3 | ... | cn |
---------------------------

有了指针,数据就在另一个星球上了,但是通过指针链接到了。数组本身就有数据。现在,多维数组只是数组的数组。数组嵌套到父数组中。所以,你的数组的大小是:

(sizeof(int) * 10) * 10

那是因为你有 10 个数组,所有数组都是 10 个整数的数组。现在,如果你想传递那个数组,它会被转换。但是为了什么?指向其第一个元素的指针。元素类型不是指针,而是数组。因此,您传递了一个指向 10 int 数组的指针:

int (*)[10] // a pointer to an int[10]

既不是int*数组,也不是int**数组。您可能会问为什么数组不作为 int** 传递。这是因为编译器必须知道行长。如果您执行 array[1][0],编译器将寻址距二维数组开头 sizeof(int) * 10 字节的位置。它以指向数组的指针类型解码该信息。

因此,您必须在上述完全等效的函数原型(prototype)中选择一个。当然,最后一个只是令人困惑。如果参数被声明为数组,编译器只会默默地忽略写入最外层维度的任何数字。所以我也不会使用倒数第二个版本。最好是使用第一个或第二个版本。重要的是要记住 C 没有(真正的)数组参数!该参数最后将是一个指针(在本例中为指向数组的指针)。

请注意上面的多维情况与下面的退化一维情况有何相似之处。以下 4 个版本都是完全等价的:

void foo(int *array);
void foo(int array[]);
void foo(int array[10]);
void foo(int array[42]);

关于c - 将数组和矩阵传递给函数作为 C 中的指针和指向指针的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/546860/

相关文章:

c - C 中的多个控制台输入

golang 为什么比较两个指向结构的变量表现不同?

c++ - 传入此函数的参数类型是什么

c++ - C++ 中 <type*[n]> 和 <type(*)[n]> 的区别

arrays - rails 强参数不接受散列数组

javascript - 通过作为参数传递和全局变量访问函数内部变量之间的区别?

c - 'GtkToggleButton {又名 struct _GtkTogglebutton }' has no member ' 事件'

c - 在 Windows 上迭代目录时查找句柄无效

c - 释放 C 中分配的内存

使用 malloc 和指针在 C 中创建 2 个随机矩阵