我正在尝试使下面的代码工作,但据我所知,有两个选项将矩阵传递给函数:
grunt
void f(int v[100][100], int n)
为什么它不会像下面的代码一样工作?不是说[100] [100]与动态分配相同吗?不是[i] [j]和*(*(a + i)+ j)相同吗?
int a[100][100]
答案 0 :(得分:4)
数组衰减到指针,这就是为什么你可以写:
void foo(int *p);
void foo(int p[]); // equivalent (use the above form)
int v[100];
foo(v);
对于多维数组,只有第一个数组"衰减"。因此矩阵(将其视为数组数组)衰减到指向数组:
void foo(int (*p)[100]);
void foo(int p[][100]); // equivalent (use the above form)
int m[100][100];
foo(m);
原因与内存布局有关:
一维数组:
char v[3] = {'a', 'b', 'c'};
| a | b | c |
正如您所看到的那样,通过char *
指针访问它是微不足道的。
二维数组:
char m[2][3] = {{'a', 'b', 'c'}, {'d', 'e', 'f'}};
| a | b | c | d | e | f |
| | |
上述数组无法衰减为char **
。 char **
会有这种布局:
| addr | addr | addr | ...
在内存中会有指向char存储的指针。
因此m
可以衰减到指向char char (*p)[3]
的数组3的指针。必须知道3
,因为它给出了引用对象的大小,这绝对需要知道:取消引用和指针算术工作(例如p++
)
char (*p)[3]:
| a | b | c | d | e | f |
| | |
所以第一个p元素p[0]
是char[3]
数组{a,b,c}
而p[1]
是char[3]
数组{d,e,f}
注意我使用char
更好地将元素显示为字符。但那些不是C字符串,因为它们不是NULL终止的。用int
代替,如果它让你更舒服。
答案 1 :(得分:1)
当一个函数参数被声明为具有数组类型时,它被调整为指向数组元素类型的指针。
因此,当一个数组作为参数传递给函数或在表达式中使用时,它会被隐式转换为指向其第一个元素的指针。
所以如果你有一个数组
int a[100][100];
并使用其名称作为某个函数的参数
some_function( a, 100 );
然后将其转换为int ( * )[100]
类型。
相应地,函数参数必须以下列方式之一声明
void f( int a[100][100], size_t n );
或
void f( int a[][100], size_t n );
或
void f( int ( *a )[100], size_t n );
所有这些声明都是等效的,并声明相同的一个函数。
您可以动态定义数组,例如
int ( *a )[100] = malloc( 100 * 100 * sizeof( int ) );
并按照上面显示的方式调用该函数
some_function( a, 100 );
但是,如果您将动态定义一维数组数组,例如
int **a = malloc( 100 * sizeof( int * ) );
for ( size_t i = 0; i < 100; i++ ) a[i] = malloc( 100 * sizeof( int ) );
然后您可以看到变量a
的类型为int **
。它与int ( *a )[100]
不同。因此该函数应该声明为
void f( int *a[100], size_t n );
或
void f( int *a[], size_t n );
或
void f( int **a, size_t n );
如您所见,显示了两个不同的数组和指针声明,以及相应的两个不同的函数声明,它们取决于数组或指针的类型。