c语言的数组、指针、函数传递释义

c语言的数组、指针、函数传递释义

c语言的数组、指针、函数传递释义
转载 by一月说C


这是个很经典的问题,学C的人可能都会有这个迷茫阶段吧,本人将对这个问题的理解,花了几天时间整理如下,希望大家给予指正。同时也希望能对初学者有所帮助。不过还是声明下本文只代表本人观点。
第一,变量。变量定义时为其指定了一个存储单元(也就是在存储地址)。也就是说一个变量对应一个存储单元。如int a=1,b,c,d……;b=c=d=……=a;它们的值都是1;但变量a,b,c,d……的存储单元是不同的,也就是说他们的地址是不同的。

第二,指针也就是地址。地址是物理存储的编号,也就是说地址只有一个。如int a=1,*p1,*p2,*p3;p1=p2=p3=&a;指针p1,p2,p3的值都为1,地址也相同。这就是他与变量的本质区别了。有这个观点我们来看一下指针赋值(其中一条只适于*p)的几个基本原则:
1、*后面接地址。
2、&后面接变量。
3、地址=地址;变量=变量;
看下面几个例子:
int a,*p,*q; p=q=&a; //&接变量,地址=地址正确。
int a,*p,*q; p=*q; //地址等于变量,不正确。
int a=20,*p; *p=a; //这个也是正确的。

第三,数组。在C语言中把数组名视为该数组首元素的地址。先看一维数组,在C语言中一维数组名指针等价。如int a[n],*p;那么则a=p;p=a;但是在C语言中对左值有要求,所以赋值语句写成a=p;是语法错误。但是,它们在实质上是等价的。比如:在函数参数传递中是可以互相传送的。
再看二维数组。它在C语言中的存储方式是线性存储,也就是说他是与一维数组的存储方式一致的。二维数组也被说成是数组的数组,就是这个意思了;还有就是二维数组不能和**p通用也是这个原理。在内在单元中它们的存储方式都一样,那C如何区分一维数组和二维数组呢?当然没有好的办法,只能换调用方式区分了。这样看一下指针和二维数组是如何互相引用的。如int a[n][m],*p;能用p=&a[0][0];或者p=a[0];来指向数组a的首址。p=a[0];又是个问题啊,怎么不加&呢。呵呵这就是数组的数组的体现了。看下面的二维数组遍历的二个例子,可能会加深下理解:
例一、int a[3][5],*p,i,j;
for(i=0;i<3;i++){
p=a[i];
for(j=0;j<4;j++)
printf("%d\n",p[j]);
}
例二、int a[3][5],*p,i;
p=a[0];
for(i=0;i<3*4;i++){
printf("%d\n",p[i]);
}
以上二个例子可以看出,从实质上是把二维数组当做一维数组处理了。那想用指针把它当做二维处理怎么办,看下面的例子:
int a[b][4],(*p)[4];
p=a;
for(i=0;i<3;i++){
for(j=0;j<4;j++)
printf("%d\n",p[i][j]);
}
可以上机试下,都能输出数组a的全部元素。^&&^

第四、二维数组。好,再来看看我们以前讨论的指针实质上都是一维地址。(*p)[n]本质上也是一维的,不然就不加括号了。一维地址是我个人的称呼,后面还会去提到二维地址。
如果你同意以上的观点那就向下看,如不同意那就关了它吧。
在看二维数组引用之前,不得不说说*和&这二个符号了,*在这里我叫它减维符,&在这里我叫他加维符。那么数组中的[]呢,我叫他特殊的减维符。特殊在哪,看这个赋值语句:int a[n],*p;*p=*(a+0);*p=a[0];它们是等价的,也就是说a[0]等价于*(a+0)。是的,它的特殊就在这里。好下面就用这个观点解决下二维数组问题。好看下面几个例子:
int a[m][n];
a<->二维地址。默认为首行首列的地址。当然这里把列看作是一维地址,行看作二维地址,元素0维。
*a<->一维地址。0列的地址.默认为首行首列的地址。
a[1]<->二维地址加1后的一维地址。也就是1行0列的地址。等同于*(a+1);
&a[1]<->按优先级处理为:&(a[1]).括号内是一维地址:1行0列的一维地址,加一维后变成1行的二维地址。
&a[1][2]<->按优先级处理&后面的是1行0列的元素即0维,加维后为1行2列的一维地址。
*(a+2)<->*后是二维地址加2即2行的地址。*减维成一维地址即2行0列的一维地址。

看了上面几个例子后,是不是感觉啰嗦呢。好,接着看就知道为什么这么说了。

(*(a+2)+3)<->最里面的括号二维地址加2即2行,然后减维成2行0列的一维地址,最后将此地址加3即2行3列的一维地址。
再来看一个:
*(*(a+0)+2)<->是不是很容易就看出了它是0行2列的元素了。
好,看到这不要以为他的用途就这些了。

第五、二维指针。呵呵这名字个人起的,你不喜欢那还叫他指向指针的指针好了。
他也遵循加减维原则。如:int **p;可以写成这样的,p[1][2].或者(*p+1)[2].按地址的维次观点能解释吧。

第六、字符数组。以前举的例子都是int型的那对于字符数组能不能应用呢。答案是肯定的。但要注意的是:用在字符处理,而不能用于串处理。因为串本身就是一个一维数组。
那怎么样直接引用串呢。在二维数组时,直接引用一维地址就可以了。当然二维数组是静态的,有缺点。所以就出现了动态的字符数组:char *a[n]。这样就避免了静态数组的缺点。那怎样理解它呢。从定义上看我们可以认为它是二维指针。这样就用二维指针的方法引用它了。当然*a[n]这种类型也可以用在数值类型上,不过麻烦些需要转化下。

第七,函数的参数传递。
呵呵,终于到这了,c语言里的精华啊。
函数的参数是按值传递的。这么说可能会有人反对,不过没关系,咱们接着往下看。
变量:有几种可能性变量传变量,变量传指针,指针传变量,指针传指针。
好分别看下.变量传变量,参数是值传递所以相当于实参给形参赋了一个值。也就是二个变量,它们在被调用函数中改变后和调用函数没一点关系了。
看下另外几种传递,都涉及到了指针。前面说过了指针就是地址,要是给指针赋值当然需要地址了,固定的存储单元只对应一个地址。如果在一个函数中改变地址中的值,那么其它引用该地址的值也会变化。也就是说参数传递的只是一个值(这里值是地址)。再来看下能改变地址中值的函数传递方式,变量传指针和指针传指针,是的只有接收的是地址的参数传递,才有可能影响其它函数。如:
void max(int *p){
……}
void main(){
int a;
max(&a);
……}
或者
void max(int &a){
……}
void main(){
int a;
max(a);
……}

第八、一维数组。前面提到了一维数组的数组名与指针等价。再结合变量传递的经验,可以很容易给出一维数组的传递方式了。
如:a是一维数组,b是与a相同类型的变量,p是指针.可用的传递关系有a<->p互相传递,&a[]<->p,p[]->b,a[]->b.

好了,现在咱就不说刚开始的时候提到的指针赋值原则中,某条只适于一维指针了,免得烦人。有了这些基础,其它函数的参数传递就很好理解了。比如二维数组、字符数组了。咱就不啰嗦了。

希望大家指正,联系QQ:1946086176
一月说C 10/12--2011

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值