近来看了很多帖子,总是有人问道怎样向被调函数传递数组(一维,二维,甚至多维)
当然这一类帖子有很多回答的,但是也不乏一些根本就没有理解数组,指针的人来回答的,他们的回答总是大致差不多的,也就是数组等同于指针
数组真的是等同与指针吗???
光靠说没有说服力,看下面lz调试的截图吧
所以这里就引出了一个问题,为什么总有人认为数组名就是指针(也有可能老师讲课的时候就是这样讲的,但是这样的老师估计也没真正明白指针和数组的含义)
这是因为当一个指针变量接受了一个数组的首地址之后,数组形式和指针形式就可以互换的比如a[2],*(p+2)
这样写是没有错的,这是因为他们在底层里面的实现都是以指针的形式来实现的,也就是数组名相当于首地址,索引就是偏移量(offset),查找一个元素就是通过首地址加上偏移量就ok了,所以这样会让人误以为数组名就是指针,其实不是,指针变量只是存储了数组的地址而不是整个数组,上图已经给出
好了,进入正题,既然已经知道数组名并非指针(只是可以这样引用)
那么一维数组既然可以通过传递数组名将数组的地址传递给被调函数,那么二维数组呢???
我我们还是来实际的调试一下便知道了
先是一维的:
编译出来,0错误,0警告,说明可以传递
下面就试着传递二维数组
出现一个错误,提示写的很清楚,类型不匹配,为什么一维数组就可以传递,但是二维数组就不能传递呢,这里不是改成二级指针了吗
这里就引出了一个问题,a到底代表是哪个地址,这是我在陈正冲的《c语言深度剖析》这本书里面看到的,觉得讲得很不错,就拿来引用一下
他是这样说的,a是数组名,也就相当于一个地址,但是这里指的是第一行的首元素的首地址,因为我们可以假想二维数组是有行列组成的
所以a+1就是下一行的地址了,这与我们想要表达成第一行的第二元素的意思大不相同,所以这里就是一个问题
然后他又说道 &a是数组的首地址,然后加1也就是向后移位当前元素的所占单位字节
所以我们就知道了问题所在,正是因为类型不匹配,那我们就强制转换一下嘛
如下:
无错误,编译成功,结果也是正确输出的(结果就不截图了)
这只是一种方法
当然我们也可以采用动态申请空间的方法,这种方法可以采用,但是因为是程序员自己申请空间,就是向堆(heap)申请空间,这里就要注意了,使用完毕之后一定要free掉,不然很容易造成内存泄露的,调试如下:
这种法制要注意不要free(p),因为那样是错误的,p只是个指针,不是内存
当然也有人用数组指针的方法,这样也不错,就不用像上面那样将二维数组看成一维数组,要将行也加入到数组元素的计算中去了
当然也有更直接的一些方法,这样虽然看起来比较笨,但是绝对是不会出错,就是在性惨重不给出一维的长度,后面的维度都给出
代码如下:
第一种
#include <stdio.h>
int sum(int a[][5],int b)
{
int sum_a=0;
for(int i=0;i<b;i++)
for(int j=0;j<5;j++)
sum_a+=a[i][j];
return sum_a;
}
int main(void)
{
int a[5][5],i,j;
for(i=0;i<5;i++)
for(j=0;j<5;j++)
a[i][j]=i*5+j;
printf("%d\n",sum(a,5));
return 0;
}
第二种
#include <stdio.h>
int sum(int a[5][5])
{
int sum_a=0;
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
sum_a+=a[i][j];
return sum_a;
}
int main(void)
{
int a[5][5],i,j;
for(i=0;i<5;i++)
for(j=0;j<5;j++)
a[i][j]=i*5+j;
printf("%d\n",sum(a));
return 0;
}
第三种(数组指针)
#include <stdio.h>
int sum(int (*a)[5],int b)
{
int sum_a=0;
for(int i=0;i<b;i++)
for(int j=0;j<5;j++)
sum_a+=a[i][j];
return sum_a;
}
int main(void)
{
int a[5][5],i,j;
for(i=0;i<5;i++)
for(j=0;j<5;j++)
a[i][j]=i*5+j;
printf("%d\n",sum(a,5));
return 0;
}
以上三种方法比较容易理解
好了,就总结这么多吧,lz主要是想让哪些对指针不是很明白的人明白指针并不是数组名,只是实现机制是一样的,可以相互使用
当然博文中有不足之处,也欢迎大家批评指针,共同学习进步O(∩_∩)O~