二维数组作为函数的参数

问题:已有二维数组a[n][m] (m,n为常量整数)

int a[n][m];

如果我们要编写一个函数对这个数组进行处理,我们应该怎样声明函数的形参,又怎样在调用函数时引入二维数组这个参数呢?

  • 首先我们来看对一维数组是怎么做的

void main()
{
    int vec[n];
    fun1(vec);    
}

对函数传参时,直接把一维数组的名字作为参数传入。

在定义函数的形参时有两种方式

void fun1(int *vec);

void fun1(int vec[]);

因为这里的vec同时也是一个指向整形的指针,指向的是数组第一位的元素,所以以上两种形参都是符合要求的。

在fun1函数的实现里面,可以通过*(vec+i)或者vec[i]来访问数组元素。

  • 那么二维数组是跟上面的方法一样吗

如果是按一维数组的方式,会写成这样

void fun2(int **a)
{
    a[i][j];
}
void main()
{
    int a[n][m];
    fun2(a);
}

这是错误的写法。原来我是错误的把二维数组的名字a理解成指针的指针,而实际上这里的a是一个指向整形数组的指针

int (*p)[m];

比如这个p就是一个指向包含m个整形元素的数组的指针,p=a的操作是合法的。

所以fun2的原型可以是以下形式(假设m=10)

void fun2(int (*mat)[10]); //假设m=10
void fun2(int mat[][10]);

这样我们就可以在函数原型中访问二维数组的元素mat[i][j]
这里我们需要注意的是在定义时多维数组的第2个及以后的下标不能为空,为什么是这样设定呢,拿二维数组举例,二维数组的元素在内存空间的地址是连续的,从mat[0][0]开始,一直到mat[0][m-1],接着是mat[1][0]到mat[1][n-1],也就是说“每一行”的数据是接在上一“行”数据的后面存放的所以mat[i][j]相对于mat[0][0]的位置是i*(m-1)+j,编译器就是通过这样的方式来从一维的存储地址中找到二维数组的元素,所以第二维的长度m的值是必须的,而第一维的长度n的值是可以省略的。

  • 如果定义形参时不知道数组的大小呢

对于一维数组来说,因为在定义形参时是不用指明数组大小的,自然没有这个问题,但是二维数组作为形参时是至少要写明第二维及以后的维度的长度,而很多时候数组的大小是不确定的,这时该怎么办呢。

这时我们可以想,如果可以像一维数组一样可以通过第一个元素的地址加上偏移量来访问数组元素就好了,实际上这是可行的。

上面提到二维数组名字a是“一个指向包含m个整形元素的数组的指针”,同一维数组名字vec指针指向的是数组的第一个元素相似,二维数组名字a指向的是二维数组中第一个“包含m个整形元素的数组”,即以0为一维坐标的这段数据的这个数组a[0],对a这个一维数组再取地址&a,就可以得到a[0][0]的地址,即整个二维数组在存储空间中的第一个数的地址,通过这个地址,再结合上面提到的求二维数组的地址偏移量的方法就可以实现通过首地址加地址偏移量的方法来访问数组的内容。所以我们可以用下面这种方式实现

void fun2(int *head,n,m)
{
    *(head+i*(m-1)+j) //访问mat[i][j]的值
}

void main()
{
    int n,m;
    ...     //给n和m赋值
    int mat[n][m];
    fun2(&mat,n,m);
}

以上理论参考自《c和指针》p159

总结:二维数组的不同主要还是因为二维数组的名字和一维数组的名字的含义不同,还有二维数组的存储方式对于语法的影响,这些都跟编译器的设定有关,更高维的数组又是什么样的设计还没了解,记得以前见过一个题提到java中二维数组必须有第一维的长度,而c中必须有第二维的长度,是因为java的二维数组是另外一种存储方式还是因为java的编译器是另外的寻址规则,这些还可以进行更加深入的探究

 

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值