如何将多维C数组传递给函数?

时间:2017-02-24 17:54:57

标签: c arrays pointers multidimensional-array

我正在学习大学课程中的C和指针,我认为除了多维数组和指针之间的相似性之外,我对这个概念有很好的把握。

我认为因为所有数组(甚至是多维数组)都存储在连续的内存中,所以你可以安全地将其转换为int*(假设给定的数组是int[]。)但是,我的教授说定义中的星数取决于数组中的维数。因此,int[]将成为int*int[][]将成为int**等。

所以我写了一个小程序来测试这个:

void foo(int** ptr)
{    
}

void bar(int* ptr)
{    
}

int main()
{
    int arr[3][4];

    foo(arr);
    bar(arr);
}

令我惊讶的是,编译器在两个函数调用上发出了警告。

main.c:22:9: warning: incompatible pointer types passing 'int [3][4]' to parameter of type
      'int **' [-Wincompatible-pointer-types]
    foo(arr);
        ^~~
main.c:8:16: note: passing argument to parameter 'ptr' here
void foo(int** ptr)
         ^
main.c:23:9: warning: incompatible pointer types passing 'int [3][4]' to parameter of type
      'int *' [-Wincompatible-pointer-types]
    bar(arr);
        ^~~
main.c:13:15: note: passing argument to parameter 'ptr' here
void bar(int* ptr)
         ^
2 warnings generated.

这里发生了什么?你怎么能改变函数调用,所以其中一个会接受数组?

我的original question被标记为重复,因为我无法弄清楚如何删除重复内容,我再次问它。

编辑:这是How to pass a multidimensional array to a function in C and C++的副本,因为我问的是如何更改函数调用本身,而不是函数签名。我知道其中一个功能是正确的,我只是不确定你会选择哪一个或如何调用它。

编辑2:这是我原来的问题的副本,但原文被错误地标记为重复,无法得到答案,所以我重新询问了。

3 个答案:

答案 0 :(得分:6)

  

但是,我的教授说定义中的星数取决于数组中的维数。因此,int[]将成为int*int[][]将成为int**等。

我真的,真的希望你只是误解了他在说什么,因为那不正确。

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则表达式为" {{ 1}} - N"的元素数组;将被转换("衰减")到类型为&#34的表达式;指向T"的指针,并且表达式的值将是第一个元素的地址。阵列。如果T是一个数组类型,你最终会得到一个指向数组的指针,而不是一个指向指针的指针。

通过一些例子:

T

在对int arr[10]; ... foo( arr, 10 ); // need to pass number of rows as a separate parameter 的调用中,表达式foo的类型为" 10个元素的数组arr"。由于它不是int或一元sizeof运算符的操作数,因此它会衰减"输入&,表达式的值将是第一个元素的地址。因此,int *的原型将是

foo

请注意,这与表达式void foo( int *arr, size_t rows ); // or int arr[]; it means the same thing in this context 的结果类型相同。 &arr[0]arr[0]个对象,因此int为我们提供&arr[0]。我,int *

到目前为止一切顺利。现在让我们看一下2D数组:

arr == &arr[0]

在这种情况下,表达式int arr[10][20]; ... foo( arr, 10 ); 具有 20元素数组arr "的类型" 10元素数组;它"衰变"表达式为"指向 20元素数组的int &#34 ;;因此,int的原型变为

foo

请记住上面所说的部分"除非它是......一元void foo( int (*arr)[20], size_t rows ); // or int arr[][20] 运算符的操作数&#34 ;?如果我们写&&arr[0]类型为" 20个元素的数组arr[0]",但会自动衰减为指针。因此,我们得到的是int类型的表达式,而不是获得int **类型的表达式。再次,int (*)[20]

现在让我们看一下3D阵列:

arr == &arr[0]

这一次,表达式int arr[10][20][30]; ... foo( arr, 10 ); 具有类型" 10元素数组 20元素数组的30个元素数组arr " 。这一次,它衰败了#34;表达式为"指向 20元素数组的int "的20元素数组,原型现在是

int

再一次,void foo( int (*arr)[20][30], size_t rows ); // or int arr[][20][30] 有一个数组类型,因此表达式arr[0]为我们提供了类型&arr[0];再次,int (*)[20][30]

高维数组的模式应该从现在开始明确。

现在,这会带来一个小问题。指向arr == &arr[0] - 元素数组的指针与指向N - 元素数组的指针的类型不同,其中M。如果您的函数原型是

N != M

然后它void foo( int (*)[20], size_t rows ); x20数组一起工作;你不能将指针传递给具有不同外部维度的数组:

N

修改

如果函数期望void foo( int (*ap)[20], size_t rows ); ... int arr1[10][20]; int arr2[20][20]; int arr3[20][30]; foo( arr1, 10 ); // okay foo( arr2, 20 ); // okay foo( arr3, 20 ); // not okay - arr3 has type int (*)[30], which is not *compatible* // with int (*)[20] 并且您有一个多维数组,那么您可以显式地将指针传递给第一个元素:

int *

答案 1 :(得分:2)

仔细检查数据类型,你会得到它。

对于函数void bar(int* ptr) {...,它需要一个int *,你必须通过一个。像

这样的东西
 bar (&(arr[0][0]));

会这样做。

也就是说,一般来说,数组与指针不同。对于大多数情况,数组衰减到指向数组的第一个元素的指针,但是再次,数据类型应该相同(或至少,兼容)。

答案 2 :(得分:0)

假设,a = [1,2,3]

这里,a是指向数组第一个元素的指针。

*a = 1 , *(a+1) = 2, *(a+2) = 3.

现在,如果a是多维数组,如[3] [4]

*a = a[0][0] , *(a+1) = a[1][0], *(a+2) = a[2][0]

*(*a + 1) = a[0][1], *(*a + 2) = a[0][2]

*(*(a+1) + 1) = a[1][1], *(*(a+1) + 2) = a[1][2]

*(*(a+2) + 1) = a[1][1], *(*(a+2) + 2) = a[1][2]

* a + any_number会更改行,但*(* a + any_number)会更改列。

在函数中,你只将指针传递给数组,这里就是a。

所以,

void bar(*a){
#access elements like told above.
}

双指针** b,表示它指向另一个指针,表示

*b = a

b的值是a的地址,* b和a具有相同的值。 但** b指向一个点的位置。

表示** b和* a具有相同的值。