编程练习思考[4]---从一道两年前的指针题再理解理解指针

重读了遍高质量C++又唤起了对指针的一些思考,记录如下。

关于指针:指针存储的是内存地址,而普通变量存储的是值,但是为什么值传递就不行,而指针传递就可以,但是究竟是什么本质的不同导致值传递和指针传递的效果不一样呢?

先来看两个链条。

指针变量名字---内存地址---内存存储值

普通变量名字---内存存储值

上面分别是指针变量和普通变量跟值之间的关系。值传递和指针传递之所以效果不一样,根本上就是由于上面这两条链的不同。举例子,比如

Int a=3

要更新这个变量,用值传递函数是这样的,需要return,才能完成值的返回。

int update(int a){

         a=4

return a

}

用指针传递是这样---------------------------------------------------------------

Int *p=&a

Int update(p){

         *p=4

}

用指针传递不需要return,我们就可以修改值了,有种隔山打牛的感觉。

 

但是究竟为什么为什么呢?

不论是值传递,还是指针传递,其实归根的目的都是为了实现对变量a的重新赋值。值传递之所以不可行,是因为不同可行域的隔离特性。值传递过程中,可行域之间唯一的通信的方式就是抛值过来,然后抛值过去,而可行域之间的抛值只是通信,并没有进行赋值操作,只有同一个可行域内才可以进行赋值操作。比如下面这个。

Int a=3

a=update(a)

从作用域的角度上int a=3是在一个作用域, intb给的是另一个作用域。而update(a)根本上只是将“一个值”扔到到另一作用域了,并没有将“变量名a对应值3”这个对应关系传递。因此,即使抛过去的3这个值再怎么变换,如果没有return这个操作,将值重新抛回来,a所在的可行域根本无法完成赋值这个过程,也就无法更新原来“变量名a—3”的这层映射关系。

那么为什么指针传递却可以完成呢?

关键的关键在于指针包含的是内存地址,是一个全局唯一的常量,全局常量的优势就是可以无视不同可行域之间的隔离,直接通过全局变量进行赋值,完成映射关系更新操作。

Int *p=&a

update(){

           *p=4

}

其实从“传递上”来看,指针传递和值传递根本上是一样的,都是值传递,只不过一个值是普通数值,一个值是一串地址数值,没有区别。核心的在于普通数值是随处可见的,即使他告诉你有个别墅是你的,你也找不到在哪里。而只要你有了别墅的地址,这个全局唯一

         总之,如果你想通过外包方式修改一个值a,你实质要做的就是给a重新赋值,就是让a等于一个新的值。

         那么我负责任的告诉你:赋值只能在同一可行域才可以完成

要么你让他们帮你把计算后的值return回来,让新的值回到自己的可行域。不然不同的可行域,值丢过去了,根本不会回来,也就无法完成赋值。

要么你就告诉他这个值的地址,也就是这个以全局为可行域的东西,通过它无视可行域的存在,指哪打哪,完成全局范围的赋值。

要么返回值,要么给全局地址,否则什么也不做让身处不同可行域的东西完成通信,简直百日做梦。

 

一个更加复杂的例子是这个

void GetMemory(char* p, int length)

{

    p = (char *)malloc(sizeof(char) * num);

}

void Test(void)

{

    char *str = NULL;

    GetMemory(str, 100);   // str 仍然为 NULL

    strcpy(str, "hello");  // 运行错误

}

猛一看,我们明明已经用了指针了,为什么还是不行,额,看多了就自然会说要用指针的指针或者加上return语句。但是如果一句话简单的说明原因呢?

这个问题其实和上面的问题实质是一样的。

从上面我们知道要让函数完成赋值(假定这个值是S)给变量的工作的话:

要么让函数计算完值value后,return值value回来,给我们的变量a。

要么把我们变量a的地址完全给函数,让他们自行搞定。

我们首先明确自己的目的是什么?就是赋值,就是给一个指针变量赋予它新的值。变量就是指针变量,值就是地址。

比方说我们指针变量是P,而地址值是0X0088,套回上面的公式,我们要做的是。

要么让函数计算完0x0088后返回来。也就是return一个地址。

要么告诉函数我们指针变量P的地址完全给函数,也就是给他们指针变量的地址。

 

因此,我们的出来,如果要实现“变量=值”

要么传值进去(就是传p进去),然后return

要么传变量的地址进去,也就是传&p( 其实就是传char **p这种指针的指针进去),不用return。

归根无论地址还是普通值,都是值。无论指针变量还是普通变量,都是包含值的变量。

 

void GetMemory(char* p, int length)

{

    p = (char *)malloc(sizeof(char) * num);

    //方法一:return p

}

//方法二

void GetMemory(char** p, int length)

{

    *p = (char *)malloc(sizeof(char) * num);

    //方法一:return p

}

void Test(void)

{

    char *str = NULL;

    GetMemory(str, 100);   // str 仍然为 NULL

    strcpy(str, "hello");  // 运行错误

}

 

最后我又从自己退了的角度想了想,对指针的指针,指针,普通变量,值这些做了一些思考,也许和实际的物理机制不太一样,请不要见怪。


通过*p这个操作,可以完成蓝线的瞬间转换过程,也就是说*p在场和a在场的效果是完全一样的。比如

Int a=3

int *p=&a

那么*p=4这个过程其实就是瞬间将指针名p变身为a的过程。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值