如何将多维C数组传递给函数? [英] How to pass a multidimensional C array to a function?

查看:102
本文介绍了如何将多维C数组传递给函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在大学课堂上正在学习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.

这是怎么回事?您如何更改函数调用,以便其中一个可以接受数组?


我的原来的问题被标记为重复项,并且由于我不知道如何删除重复项,因此我再次提出要求.

这不是解决方案

但是,我的教授说,定义中的恒星数量取决于阵列中维数的数量.因此,int[]将成为int*int[][]将成为int**,依此类推.

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

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则类型为"N-"将被转换(衰减")为指向T的指针"类型的表达式,该表达式的值将是数组第一个元素的地址.如果T是数组类型,则使用指向数组的指针,而不是指向指针的指针.

通过一些示例:

int arr[10];
...
foo( arr, 10 ); // need to pass number of rows as a separate parameter

在对foo的调用中,表达式arr的类型为"int的10个元素的数组".由于它不是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 *. IOW,arr == &arr[0].

到目前为止,一切都很好.现在让我们看一个2D数组:

int arr[10][20];
...
foo( arr, 10 );

在这种情况下,表达式arr的类型为" 20个元素的int 的10个元素的数组";它衰减"为类型为指向 20个元素的int 数组的指针"的表达式;因此,foo的原型变为

void foo( int (*arr)[20], size_t rows ); // or int arr[][20]

还记得上面所说的部分吗?除非它是...一元&运算符的操作数"?如果我们编写&arr[0],则arr[0]的类型为"int的20个元素的数组",但是 not 不会自动衰减为指针.因此,我们没有得到类型为int **的表达式,而是得到了类型为int (*)[20]的表达式.同样,arr == &arr[0].

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

int arr[10][20][30];
...
foo( arr, 10 );

这次,表达式arr具有类型"的10个元素的数组,int 的30个元素的数组".这次,它衰减"为一个类型为指向 20个元素的数组,该元素包含int 的30个元素的数组"的表达式,现在的原型是

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 -element数组的指针与指向M -element数组(其中N != M)的指针的类型不同.如果您的函数原型是

void foo( int (*)[20], size_t rows );

然后它将仅在> x20数组中使用;您不能将其传递给具有不同外部尺寸的数组的指针:

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 *并且您有一个多维数组,则可以将指针显式传递给第一个元素:

void foo( int *, size_t size );
...
int arr2[10][20];
int arr3[20][10][5];

foo( &arr2[0][0], sizeof arr2 / sizeof arr2[0][0] );
foo( &arr3[0][0][0], sizeof arr3 / sizeof arr3[0][0][0] );

I'm learning about C and pointers in my university class, and I think I've got a pretty good grasp on the concept except for the similarity between multidimensional arrays and pointers.

I thought that since all arrays (even multidimensional) ones are stored in contiguous memory, you could safely convert it to a int* (assuming the given array is an int[].) However, my professor said that the number of stars in the definition depends on the number of dimensions in the array. So, an int[] would become an int*, a int[][] would become an int**, etc.

So I wrote a small program to test this:

void foo(int** ptr)
{    
}

void bar(int* ptr)
{    
}

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

    foo(arr);
    bar(arr);
}

To my surprise, the compiler issued warnings on both function calls.

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.

What's going on here? How could you change the function calls so one of them would accept the array?


My original question got marked as a duplicate, and since I can't figure out how to get the duplicate removed I'm asking it again.

Edit: This is not a duplicate of How to pass a multidimensional array to a function in C and C++ because I'm asking how to change the function calls themselves, not the function signatures. I know one of these functions is correct, I'm just not sure which one or how you would go about calling it.

Edit 2: This is a duplicate of my original question, but the original was wrongly marked as a duplicate and couldn't get answered so I re-asked it.

解决方案

However, my professor said that the number of stars in the definition depends on the number of dimensions in the array. So, an int[] would become an int*, a int[][] would become an int**, etc.

I'm really, really hoping you simply misunderstood what he was saying, because that's not correct.

Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. If T is an array type, you wind up with a pointer to an array, not a pointer to a pointer.

Going through some examples:

int arr[10];
...
foo( arr, 10 ); // need to pass number of rows as a separate parameter

In the call to foo, the expression arr has type "10-element array of int". Since it's not the operand of the sizeof or unary & operators, it "decays" to type int *, and the value of the expression will be the address of the first element. Thus, the prototype for foo would be

void foo( int *arr, size_t rows ); // or int arr[]; it means the same thing in this context

Notice that this is the same type as the result of the expression &arr[0]. arr[0] is an int object, so &arr[0] gives us an int *. IOW, arr == &arr[0].

So far so good. Now let's look at a 2D array:

int arr[10][20];
...
foo( arr, 10 );

In this case, the expression arr has type "10-element array of 20-element array of int"; it "decays" to an expression of type "pointer to 20-element array of int"; thus, the prototype for foo becomes

void foo( int (*arr)[20], size_t rows ); // or int arr[][20]

Remember the part above where it says "except when it is the operand of ... the unary & operator"? If we write &arr[0], arr[0] has type "20-element array of int", but it does not automatically decay to a pointer. So instead of getting an expression of type int **, we get an expression of type int (*)[20]. So again, arr == &arr[0].

Now let's look at a 3D array:

int arr[10][20][30];
...
foo( arr, 10 );

This time, the expression arr has type "10-element array of 20-element array of 30-element array of int". This time, it "decays" to an expression of type "pointer to 20-element array of 30-element array of int", and the prototype is now

void foo( int (*arr)[20][30], size_t rows ); // or int arr[][20][30]

And once again, arr[0] has an array type, so the expression &arr[0] gives us the type int (*)[20][30]; again, arr == &arr[0].

The pattern for higher-dimensioned arrays should be clear from here on out.

Now, this brings up a minor issue. A pointer to an N-element array is a different type from pointer to an M-element array, where N != M. If your function prototype is

void foo( int (*)[20], size_t rows );

then it will only work with Nx20 arrays; you cannot pass it a pointer to an array with a different outer dimension:

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]

EDIT

In the case where a function is expecting an int * and you have a multi-dimensional array, you'd explicitly pass a pointer to the first element:

void foo( int *, size_t size );
...
int arr2[10][20];
int arr3[20][10][5];

foo( &arr2[0][0], sizeof arr2 / sizeof arr2[0][0] );
foo( &arr3[0][0][0], sizeof arr3 / sizeof arr3[0][0][0] );

这篇关于如何将多维C数组传递给函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆