混淆指针和多维数组 [英] Confusion about pointers and multidimensional arrays
问题描述
如果以下是可能的:
的MyFunction(INT *数组,INT大小)
{
的for(int i = 0; I<大小;我++)
{
的printf(%d个,数组[我]);
}
}主要()
{
int数组[6] = {0,1,2,3,4,5};
MyFunction的(数组,6);
}
为什么下面是不是?
的MyFunction(INT **阵列,诠释行,诠释山口)
{
的for(int i = 0; I<排;我++)
{
对于(INT J = 0; J<西; J ++)
{
的printf(%d个,数组[I] [J]);
}
}
}主要()
{
int数组[3] [3] = {0,1,2,3,4,5,6,7,8};
MyFunction的(阵列,3,3);
}
首先,一些的标准语言:
6.3.2.1左值,数组和功能代号的结果
...结果
3除非当该值是sizeof运算符或单目&运算符的操作数,或者是用于初始化数组,即具有类型的前pression文字字符串类型的数组转换为前pression,类型为指针输入指向数组对象的初始元素,不是左值。如果数组对象有注册存储类,这种行为是未定义。
块引用>由于声明
INT myArray的[3] [3];
的键入的
myarray中
是3个元素的数组的3元素数组的INT
。由规则上面去,当你写MyFunction的(myarray中,3,3);
的前pression 的
myarray中
已经从3元的三元素数组的类型隐式转换(衰变)INT
到指向的三元素数组INT
,或的int数组(*)[3]
。这样,你的函数原型将需要
INT的MyFunction(INT(*数组)[3],诠释行,诠释山口)
注意
INT **阵列
为不可以一样INT(*数组)[3]
;指针运算将是不同的,所以你的下标将不拉闸指向正确的地方。请记住,数组索引是的定义的在指针运算方面:A [I]
==*(A + I)
,A [I] [J] == *(*(A + I)+ J)
。A + I
将根据产生不同的值是否A
是INT **
或INT(*)[N]
。这个特殊的例子假定你总是传递
INT
的NX3元素的数组;不,如果你想,以应付任何的N×M大小的数组非常灵活。要解决这个问题的方法之一是明确地传递数组的第一个元素的的地址的,所以你只是传递一个简单的指针,然后计算出正确的手动偏移:无效MyFunction的(INT *改编,诠释行,诠释山口)
{
INT I,J;
对于(i = 0; I<排;我++)
为(J = 0; J<西; J ++)
的printf(%d个,一个[我* COL + J]);
}INT主要(无效)
{
INT myArray的[3] [3] = {{1,2,3},{4,5,6},{7,8,9}};
...
MyFunction的(安培; myArray的[0] [0],3,3);由于我们通过一个简单的指针
INT
,我们不能用在双标MYFUNC
;的改编结果[I]
是一个整数,而不是一个指针,所以我们必须要计算全偏移在一个下标操作的数组。请注意,这一招只对真正的多维数组。现在,一个
**
的可以的表明,在一个2-D结构组织的价值观,但建一个不同的方法之一。例如:无效AnotherFunc(INT **改编,诠释行,诠释山口)
{
INT I,J;
对于(i = 0; I<排;我++)
为(J = 0; J<西; J ++)
的printf(%d个,编曲[I] [J]);
}INT主要(无效)
{
INT D0 [3] = {1,2,3};
INT D1 [3] = {4,5,6};
INT D2 [3] = {7,8,9}; 为int *一个[3] = {D0,D1,D2}; AnotherFunc(一,3,3);
...
}由规则去上面,当前pressions
D0
,D 1
和<$ C > $ C> D 2 出现在初始化为,它们的类型都是从
为int的3元素数组转换
到指针INT
。同样,当前pressionA
出现在调用AnotherFunc
,其类型从3转换指针-element阵列INT
,以指针的指针的INT
。请注意,在
AnotherFunc
我们下标两个维度,而不是计算偏移就像我们在MYFUNC
一样。这是因为A
是指针的值的数组。这位前pression改编[I]
我们得到第i的指针的值从位置偏移改编
;我们再找到第j个整数值从指针值的偏移量。下面的表格可以帮助 - 它显示的类型不同的阵列前pressions和它们衰变什么根据它们的声明(
T(*)[N]
是指针类型,不是数组类型,因此它不衰减):
声明防爆pression类型隐式转换(衰变)到
----------- ---------- ---- ------------------------- -------
T A [N]一个T [N] T *
&一个T(*)[N]
*在
一个[我] T ... T A [M] [N]一个T [M] [N] T(*)[N]
&一个T(*)[M] [N]
*一个T [N] T *
一个[I] T [N] T *
&A [I] T(*)[N]
*一个[我] T ...
一个[I] [J] T ...T A [L] [M] [N]一个T [L] [M] [N] T(*)[M] [N]
&一个T(*)[L] [M] [N]
*一个T [M] [N] T(*)[N]
一个[I] T [M] [N] T(*)[N]
&一个[I] T(*)[M] [N]
* A [I] T [N] T *
一个由[i] [j]的T [N] T *
&A [I] [J] T(*)[N]
* A [I] [J] T ...
一个由[i] [j]的[K] T ...有关高维阵列模式应该是清楚的。
If the following is possible:
MyFunction(int *array, int size) { for(int i=0 ; i<size ; i++) { printf("%d", array[i]); } } main() { int array[6] = {0, 1, 2, 3, 4, 5}; MyFunction(array, 6); }
Why the following is not?
MyFunction(int **array, int row, int col) { for(int i=0 ; i<row ; i++) { for(int j=0 ; j<col ; j++) { printf("%d", array[i][j]); } } } main() { int array[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; MyFunction(array, 3, 3); }
解决方案First, some standard language:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.Given the declaration
int myarray[3][3];
the type of
myarray
is "3-element array of 3-element array ofint
". Going by the rule above, when you writeMyFunction(myarray, 3, 3);
the expression
myarray
has its type implicitly converted ("decay") from "3-element array of 3-element array ofint
" to "pointer to 3-element array ofint
", orint (*)[3]
.Thus, your function prototype would need to be
int MyFunction(int (*array)[3], int row, int col)
Note that
int **array
is not the same asint (*array)[3]
; the pointer arithmetic will be different, so your subscripts won't wind up pointing to the right places. Remember that array indexing is defined in terms of pointer arithmetic:a[i]
==*(a+i)
,a[i][j] == *(*(a + i) + j)
.a+i
will yield a different value depending on whethera
is anint **
or anint (*)[N]
.This particular example assumes you're always passing an Nx3-element array of
int
; not terribly flexible if you want to deal with any NxM-sized array. One way to get around this would be to explicitly pass the address of the first element in the array, so you're just passing a simple pointer, and then compute the proper offset manually:void MyFunction(int *arr, int row, int col) { int i, j; for (i = 0; i < row; i++) for (j = 0; j < col; j++) printf("%d", a[i*col+j]); } int main(void) { int myarray[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; ... MyFunction(&myarray[0][0], 3, 3);
Since we pass a simple pointer to
int
, we can't use a double subscript inMyFunc
; the result ofarr[i]
is an integer, not a pointer, so we have to compute the full offset into the array in the one subscript operation. Note that this trick will only work for truly multidimensional arrays.Now, a
**
can indicate values that are organized in a 2-D structure, but one that was built a different way. For example:void AnotherFunc(int **arr, int row, int col) { int i, j; for (i = 0; i < row; i++) for (j = 0; j < col; j++) printf("%d", arr[i][j]); } int main(void) { int d0[3] = {1, 2, 3}; int d1[3] = {4, 5, 6}; int d2[3] = {7, 8, 9}; int *a[3] = {d0, d1, d2}; AnotherFunc(a, 3, 3); ... }
Going by the rule above, when the expressions
d0
,d1
, andd2
appear in the initializer fora
, their types are all converted from "3-element array ofint
" to "pointer toint
". Similarly, when the expressiona
appears in the call toAnotherFunc
, its type is converted from "3-element array of pointer toint
" to "pointer to pointer toint
".Note that in
AnotherFunc
we subscript both dimensions instead of computing the offset like we did inMyFunc
. That's becausea
is an array of pointer values. The expressionarr[i]
gets us the i'th pointer value offset from the locationarr
; we then find the j'th integer value offset from that pointer value.The following table might help - it shows the types of various array expressions and what they decay to based on their declarations (
T (*)[N]
is a pointer type, not an array type, so it doesn't decay):Declaration Expression Type Implicitly Converted (Decays) to ----------- ---------- ---- -------------------------------- T a[N] a T [N] T * &a T (*)[N] *a T a[i] T T a[M][N] a T [M][N] T (*)[N] &a T (*)[M][N] *a T [N] T * a[i] T [N] T * &a[i] T (*)[N] *a[i] T a[i][j] T T a[L][M][N] a T [L][M][N] T (*)[M][N] &a T (*)[L][M][N] *a T [M][N] T (*)[N] a[i] T [M][N] T (*)[N] &a[i] T (*)[M][N] *a[i] T [N] T * a[i][j] T [N] T * &a[i][j] T (*)[N] *a[i][j] T a[i][j][k] TThe pattern for higher-dimensional arrays should be clear.
这篇关于混淆指针和多维数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!