然而,我的教授说,定义中的星星数量取决于数组中的维数。所以,一个int[]
将成为一个int*
, a int[][]
将成为一个int**
, etc.
我真的,really希望你只是误解了他的话,因为那是不正确的。
除非它是操作数sizeof
或一元&
运算符,or 是用于初始化声明中的字符数组的字符串文字,类型为 " 的表达式N
-元素数组T
” 将被转换(“衰减”)为“指向的指针”类型的表达式T
",表达式的值将是数组第一个元素的地址。如果T
是一个数组类型,你最终会得到一个指向数组的指针,而不是指向指针的指针。
通过一些例子:
int arr[10];
...
foo( arr, 10 ); // need to pass number of rows as a separate parameter
在通话中foo
, 表达方式arr
具有类型“10 元素数组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]
is an int
对象,所以&arr[0]
给我们一个int *
. IOW, arr == &arr[0]
.
到目前为止,一切都很好。现在让我们看一个二维数组:
int arr[10][20];
...
foo( arr, 10 );
在这种情况下,表达式arr
具有类型“10 元素数组20 元素数组int
”;它“衰减”为“指向的指针”类型的表达式20 元素数组int
“;因此,原型为foo
becomes
void foo( int (*arr)[20], size_t rows ); // or int arr[][20]
记住上面的部分,它说“除非它是......一元的操作数”&
运算符”?如果我们写&arr[0]
, arr[0]
具有类型“20 元素数组int
“,但确实如此not自动衰减为指针。所以不要获取类型的表达式int **
,我们得到一个类型的表达式int (*)[20]
。再说一次,arr == &arr[0]
.
现在让我们看一个 3D 数组:
int arr[10][20][30];
...
foo( arr, 10 );
这次的表情arr
具有类型“10 元素数组20 元素数组 30 元素数组int
这一次,它“衰减”为“指向的指针”类型的表达式20 元素数组 30 元素数组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 );
那么它就会only与...一起工作N
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]
EDIT
在函数期望的情况下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] );