指针详解

初探指针

首先我们定义一个指针变量p,代码为:

int *p;

这个时候就会给p开辟一个内存空间,简单地图示为(至于这个内存空间在哪里,先对其不言):

 

接下来我们现在定义一个int变量a,代码为:

int a;

那么同样会在一个地方给a开辟一个内存空间,图示为:

接下来给a赋值,代码为:

a=1;

此时图示表示为:

也就是说将一个有符号的整型数字1放到了a的内存空间中。那么,如果是一个指针的内存空间中,应该放什么样的值?答案是放一个地址的值,也就是说p中应当放一个地址的值(这个值是一个以当前系统寻址范围为取值范围的整数)。

比如假设a这个内存空间的地址为250(当然1703740这种复杂的数字似乎更符合实际,但

 

为了简便书写就用250),我们可以想象a中的数据都放在一个门牌号码为250的房间。

然后我们使用代码

p=&a;

这样就使p指向a,具体地说就是把a的地址作为一个值放到了p的内存空间中,我们可以想象此时p房间中有一张写有a地址的小纸条。此时p图示为:

此时,代码p的值就是这张小纸条上面写的数字而已,而代码*p也就是我们在p房间中发现了这张写着250的小纸条,并按指示到250号码的房间取走那里的东西,然后我们去了250号房间(也就是a的房间),把里面的数据1取了出来。所以*p的值也就是1了。

 

野指针和空指针

其实,在最开始我们定义了一个指针变量之后,在没有对其初始化的情况下(也就是内存空间里面没有放任何有效的地址),它就是一个野指针。野指针指向一个已删除的对象或未申请访问受限内存区域的指针,或者更通俗的说法是指向垃圾内存的指针。所以在没有在p这个房间里面放任何“写着有效地址纸条”的情况下,不可以*p操作(当然不是定义时候的*p)。

(用最low的比喻:野指针就是在这个指针的房间里面放了一张骂程序的话的纸条,所以除非你换了一张写着正常地址的纸条,就不要用*p操作去执行这张纸条里的内容。一旦你用*p操作去执行野指针房间里面的那张纸条的内容的话,程序看完就生气崩溃了。。。)

 

空指针就是内存空间中放着空指针值(这个空指针值就是NULL)的指针变量。对于空指针值,一般的文档中倾向于用 NULL 表示,而没有直接说成 0。但是我们应该清楚:对于指针类型来说,返回 NULL 返回0是完全等价的,因为 NULL 0 都表示 “null pointer”(空指针)。

故而如果我们在定义了一个指针变量之后,不打算马上使用它(将其初始化),就应该将其赋值为NULL,以避免使用野指针的危险。

用最low的比喻:空指针就是在这个指针的房间里放了一张纸条,用*p去执行上面的指令发现上面写着“对不起,这里没有有效值,请下次再来”,虽然程序也同样无法根据纸条内容去其它房间取东西,但至少这张纸条上面语气比较柔和,程序表示目前情绪比较稳定,不会崩溃,还是会接着干活的。

 

指针传值

承接上文,已经有了pa,并且p已经指向a了。如果我们现在又定义了一个指针:

int *p2;

并且我们如此操作

p2=p;

此时p中的值(也就是那张寻址用的小纸条)会赋给p2,也就是说p2内存空间中放了a的门牌号250

这里尤其需要注意,当左=右时,如果左为指针变量,右为普通变量,则此时是右边内存空间的地址值放到了左边。而若左右都为指针变量,则是右边指针的值(即之前所比作的房间里所存放的地址纸条)放到了左边指针变量的空间(房间)里。

从以下程序结果可以很明显看出:

注意这里尤其不可认为p2=p1是把p1变量本身的地址(即p1房间的门牌号)记录在了p2中。

 

指针作为函数参数

关于C语言参数传递方式,有人说只有一种就是值传递,有人说有两种值传递和地址传递本人倾向于第一种说法,但第二种说法也容易理解,它只是把第一种说法更加细分了,也就是它认为把指针作为参数的时候叫地址传递。至于两种说法哪一种更具权威性就不探究了,毕竟只是分类而已。

首先我们来看程序

这个程序就不多解释了,无非就是改变了形参的值却没有改变实参的值。

所以我们也就多使用一下方法:

这里我们看它为什么会成功。在运行程序的时候,我们假设实参的ab两个变量叫做a1b1以示区别,形参的ab两个指针叫做a2b2。这个时候参数传递的时候a1b1的地址值(门牌号码数)作为数据放到了a2b2中,这样a2b2就可以顺着这两个地址去改变a1b1中的值。

然后我们接下来看另一个程序:

这时我们会发现swap中又没有交换成功,因为C语言函数中参数始终都只能传递值(地址作为特殊的值也是值,一串数字而已),我们试图交换形参a和形参b房间中的那个小纸条,虽然在函数中可以成功,但在函数外实参a和实参b的地址和地址中的值并没有任何变化。

 

二级指针

从上一个问题看,我们有没有办法可以试图改变ab本身的地址呢?这里就用到了二级指针。

清空前面的假设,现做如此代码:

我们假设a的地址为250p本身的地址(即p房间的门牌号)为10086,至于double_p本身的地址我们现在不用管。图示为(为了区分普通值和地址值,我们将地址值用红色表示):

这个时候double_p的值就是10086p的存储空间所在处)。那么*double_p就是从double_p这个房间中取出纸条,上面告诉你去10086房间读纸条上面的数字然后继续待命,也就是说*double_p值为250。而**double_p就是从double_p这个房间中取出纸条,随之去10086房间取纸条,然后看到纸条上面告诉你去拿250号房间里面的数据,然后就去执行了。

故而才有下面的程序:

在一般情况下,我们最多用到二级指针,故而不说二级以上的了。

 

指针与const

这个主要是概念问题,可以参看博文

https://blog.csdn.net/come_from_pluto/article/details/87917678

 

以上如果理解了,函数指针、指针返回值、指针数组等剩余问题都容易解决。

 

转载请标明出处,原文地址:https://blog.csdn.net/come_from_pluto

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值