小比特学习值传递和地址传递

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

请跟我学习两种传递的不同,以下内容借鉴印度顶尖程序员,感谢他的无私分享和极其深刻的教学,让我深刻理解C语言中的指针


提示:以下是本篇文章正文内容,下面案例可供参考

一、内存的四个分区·

堆区(heap):一般由程序员手动分配释放(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收。
栈区(stack):由编译器自动分配释放,存放函数的形参、局部变量等。当函数执行完毕时自动释放。
全局区(global / stack):用于存放全局变量和静态变量, 里面细分有一个常量区,一些常量存放在此。该区域是在程序结束后由操作系统释放。
代码区(code / text):用于存放程序代码,字符串常量也存放于此。

                                    å¨è¿éæå¥å¾çæè¿°


 

二、

假设新手程序员Albert刚刚学习了关于函数的用法,写了这样的程序:

#include <stdio.h>

void Incremnet(int a){
    a = a + 1;
}

int main(){
    int a;
    a = 10;
    Incremnet(a);
    printf("a = %d\n", a);

    return 0;
}

在该程序中,Albert期望通过Increment()函数将a的值加1,然后打印出a = 11,但是,程序的实际运行结果却是a = 10。问题出在哪里呢?

实际上,这种函数调用的方式称为值传递call by value,这样在Increment()函数中,临时变量local variable a,会在该函数结束后立刻释放掉。也就是说Increment()函数中的a ,和main() 函数中的 a 并不是同一个变量。我们可以分别在Increment()和main()两个函数内打印变量a的地址:

printf("Address of a in Increment: %d", &a);
printf("Address of a in main: %d", &a);            // 将这两句分别放在Increment函数和main函数中

输出:

Address of a in Increment: 2063177884
Address of a in main: 2063177908

这里两个地址的具体值不重要,重要的是他们是不一样的,也就是说我们在两个函数中操作的a变量并不是同一个,所以程序输出的是没有加1过的a的值。

笔者这里还是根据原视频作者的讲解,通过画出内存的形式来分析值传递。

å¨è¿éæå¥å¾çæè¿°

程序会为每个函数创造属于这个函数的栈帧,我们首先调用main()函数,其中的变量a一直存储在main()函数自己的栈帧中。在我们调用Increment()函数的时候,会单独为其创造一个属于它的栈帧,然后main()函数将实参a=10传给Increment()作为形参,a会在其中加1,但是并没有被返回。在Increment()函数调用结束后,它的栈帧被释放掉,main()函数并不知道它做了什么,main()自己的变量值一直是10,然后调用printf()函数,将该值打印出来。

可以看到,局部变量的值的生命周期随着被调用函数Increment()的结束而结束了,而由于main()中的a和Incremet()中的a并不是同一个变量(刚才已经看到,二者并不在同一地址),因此最终打印出的值还是10。
 

那怎样才能实现Albert的预期呢?我们刚才已经看到,之所以最终在main()中打印的值没有加1,就是因为加1的变量和最终打印的变量不是同一个变量。那我们只要使得最终打印的变量就是在Increment()中加过1的变量就可以了。这要怎么实现呢?我们刚刚学过,通过指针可以指向某个特定的变量,并可以通过解引用的方式对该变量再进行赋值,而又由于在程序未执行结束时,main()函数里分配的空间均可以被其他自定义函数访问。因此我们可以将main()中的变量地址传给Increment(),在其中对该地址的值进行加一,这样最终打印的变量就会是加过1的了。

å¨è¿éæå¥å¾çæè¿°

实现如下:

#include <stdio.h>

void Incremnet(int* p){
    *p = *p + 1;
}

int main(){
    int a;
    a = 10;
    Incremnet(&a);
    printf("a = %d\n", a);

    return 0;
}

这种传地址的方式我们称之为call by reference。

它可以在原地直接修改传入的参数值。另外,由于传的参数是一个指针,无论被指向的对象有多么大,这个指针也只占4个字节(32位机),因此,这种方式也可以大大提高传参的效率。
 


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值