如何将二维数组作为函数的参数传递
今天写程序的时候要用到二维数组作参数传给一个函数,我发现将二维数组作参数进行传递还不是想象得那么简单里,但是最后我也解决了遇到的问题,所以这篇文章主要介绍如何处理二维数组当作参数传递的情况,希望大家不至于再在这上面浪费时间。
正文:
首先,我引用了谭浩强先生编著的《C程序设计》上面的一节原文,它简要介绍了如何
将二维数组作为参数传递,原文如下(略有改变,请原谅):
[原文开始]
可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如:
void Func(int array[3][10]);
void Func(int array[][10]);
二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的:
void Func(int array[][]);
因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,下面写法是错误的:
void Func(int array[3][]);实参数组维数可以大于形参数组,例如实参数组定义为:
void Func(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;
从以上可以看出,如果我们省略了第二维或者更高维的大小,编译器将不知道如何正确的寻址。但是我们在编写程序的时候却需要用到各个维数都不固定的二维数组作为参数,这就难办了,编译器不能识别阿,怎么办呢?不要着急,编译器虽然不能识别,但是我们完全可以不把它当作一个二维数组,而是把它当作一个普通的指针,再另外加上两个参数指明各个维数,然后我们为二维数组手工寻址,这样就达到了将二维数组作为函数的参数传递的目的,根据这个思想,我们可以把维数固定的参数变为维数随即的参数,例如:
void Func(int array[3][10]);
void Func(int array[][10]);
变为:
void Func(int **array, int m, int n);
在转变后的函数中,array[i][j]这样的式子是不对的(不信,大家可以试一下),因为编译器不能正确的为它寻址,所以我们需要模仿编译器的行为把array[i][j]这样的式子手工转变为:
*((int*)array + n*i + j);
在调用这样的函数的时候,需要注意一下,如下面的例子:
int a[3][3] =
{
{1, 1, 1},
{2, 2, 2},
{3, 3, 3}
};
Func(a, 3, 3);
根据不同编译器不同的设置,可能出现warning 或者error,可以进行强制转换如下调用:
Func((int**)a, 3, 3);
对二维数组的理解,可以从下面几种表示方法进行:
1. a[0],a[1],...,a[N] 表示的是二维数组每一行的首地址;
2. a 指向一维数组{a[0],a[1],a[2],...}的首地址;
3. a[1]+2 表示指向二维数组第二行第三列的首地址;
4. *a[0],*a[i],...,表示指向第 i 行的二维数组的首地址的元素值(等同于a[0][0],a[i][0])
5. 比较难理解,但是比较重要的一点:我们知道,一维数组中*(a+i) = a[i] ,此假设对二维数组也是无条件等价的。
1 #include <iostream> 2 using namespace std; 3 4 5 void func1(int *array,const int m,const int n) 6 { 7 const int M = m; 8 int arrayList[10][10] = {0}; 9 for (int i =0;i<M;i++) 10 { 11 for (int j = 0;j<M;j++) 12 { 13 arrayList[i][j] = *(array+n*i+j); 14 cout<<' '<<arrayList[i][j]; 15 } 16 cout<<endl; 17 } 18 19 20 } 21 void main() 22 { 23 24 int a[5][5] = {{1,2,3,4,5},{1,3,4,5,6},{3,4,5,6,7},{1,4,6,7,8},{3,4,5,6,7}}; 25 int b[3]={4,2,7}; 26 cout<<a<<endl; 27 cout<<a[0]<<endl; 28 cout<<&a[0]<<endl; 29 cout<<*a<<endl; 30 cout<<*a[2]<<endl; 31 func1((int*)a,5,5); 32 cout<<b<<endl; 33 cout<<*b<<endl; 34 35 }