二维数组作为函数参数调用过程中:
void Fun(**a, m, n)
{
//....
}
//....
Fun(a,m,n);
调用函数过程中,会发现VS报错:
//IntelliSense: "int (*)[3]" 类型的实参与 "int **" 类型的形参不兼容
这怎么难得倒我?反手一个Ctrl+C Ctrl + V 百度一下,原来强制类型转换一下就ok!
Fun((int **)a,m,n);
编译 没有错误! 运行 啪啪打脸。。。
正文开始:
可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如:
void Fun(int array[3][10]);
void Fun(int array[][10]);
二者定义等价,但是不能省略二维数组的第二维,如下面是错误的:
void Fun(int array[][]);
这是因为:从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列。
这也就能解释为什么实参数组维数可以大于形参数组(这时形参数组只取实参数组的一部分,其余部分不起作用 ),例如实参数组定义为:
void Fun(int array[3][10]);
而形参数组定义为:
int array[5][10];
课本总结:将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的。
究其更深原因,编译器处理数组的过程为:
对于数组:
int p[M][N];
如果要取p[i][j]的值(i>=0 && i<M && 0<=j && j < N),编译器是这样寻址的,它的地址为:
p + i*N + j;
因此,如果省略了第二维的大小,编译器将不知道如何寻址。
但是我们在编写程序的时候却需要用到各个维数都不固定的二维数组 作为参数,一个解决办法是:
不把二维数组当作一个二维数组,而是把它当作一个普通的指针,再另外加上两个参数指明各个维数,然后为二维数组手工寻址,这样就达到了将二维数组作为函数的参数传递的目的,根据这个思想,可以把维数固定 的参数变为维数随即的参数。
这也就能解释刚刚强制类型转换后运行没有结果的原因了,我们需要模仿编译器的行为把array[i][j]这样的式子手工转变为:
*((int*)array + n*i + j);
至此,二维数组作为函数参数传递的问题就可以解决了。