如何将多维C数组传递给函数? [英] How to pass a multidimensional C array to a function?
问题描述
我在大学课堂上正在学习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个元素的数组";它衰减"为类型为指向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 );
然后它将仅在
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 anint*
, aint[][]
would become anint**
, 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 N
x20 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屋!