我正在学习大学课程中的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:这是我原来的问题的副本,但原文被错误地标记为重复,无法得到答案,所以我重新询问了。
答案 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具有相同的值。