0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言函数参数关于传值和传指针有什么区别?

黄工的嵌入式技术圈 来源:编程珠玑 作者:守望先生 2020-02-26 16:35 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

前言

函数传参有三种传参方式:传值、传址、传引用。

我们可能听过C语言中的传值和传指针,在其他语言中,也有传引用一说,那么他们到底有什么区别呢?如果你还不能准确地分辨,就该好好了解一下了。

传值

我们在初学C语言的时候就被老师教过,下面的方式是无法交换a和b的值的:

#include voidswap(inta,intb) { inttemp=a; a=b; b=temp; printf("swapa=%d,b=%d\n",a,b); } intmain(void) { inta=10; intb=20; printf("beforeswap:a=%d,b=%d\n",a,b); swap(a,b); printf("afterswap:a=%d,b=%d\n",a,b); return0; }

运行结果如下:

beforeswap:a=10,b=20 internalswapa=20,b=10 afterswap:a=10,b=20

可以看到,a和b的值最终并没有被交换。开始时a,b的值为10,20,而最终还是同样的值。

为什么呢?因为函数参数在传递的时候,都是传原数据的副本,也就是说,swap内部使用的a和b只是最初始a和b的一个副本而已,所以无论在swap函数内部对a和b做任何改变,都不会影响初始的a和b的值。

正因如此,我们常常被告知,不要把直接把结构体直接作为参数,这样效率会很低。由于结构体本身占用字节数较大,如果直接作为参数,那么将会产生一个较大的”副本“,如此一来,效率也就很低了。

我们再结合下面的图来理解:

值传递

首先图中方框中的上部分a和b代表了main函数中的a和b,即原始数据,而方框中的下部分a和b代表了函数的参数a和b,即原始数据的“副本”。(后面的图都是如此,上部分代表原始值,下部分代表函数参数值)。

调用swap函数前后的情形如下:

调用swap前后

由于在swap中永远只是对a和b的副本进行操作,因此完全不影响原始的a和b的值。最终也不可能达到交换a和b的值的目的。

传指针

那么为解决上面的问题,我们知道,需要传指针。其代码如下:

#include voidswap(int*a,int*b) { inttemp=*a; *a=*b; *b=temp; printf("swapa=%d,b=%d\n",*a,*b); } intmain(void) { inta=10; intb=20; printf("beforeswap:a=%d,b=%d\n",a,b); swap(&a,&b); printf("afterswap:a=%d,b=%d\n",a,b); return0; }

运行结果:

beforeswap:a=10,b=20 swapa=20,b=10 afterswap:a=20,b=10

可以看到在这种情况下,a,b的值才是真正交换了。

为什么又有传值,又有传指针

看到这里,不知道你是否会疑惑,为什么给函数传递参数的时候,一会是传值,一会是传指针呢?为什么传指针就能改变参数的值呢?实际上,C语言里,参数传递都是值传递!也就是说,你认为的传指针也是传值,只不过它的值是指针类型罢了。

我们再通过图来理解前面为什么传指针就可以交换a,b的值:

从图中可以看出,虽然传递给函数的是指向a和b的指针的副本,但是它的副本同样也是指向a和b,因此虽然不能改变指针的指向,但是能改变参数a和b指向的内容,即改变原始a和b的值。

再看传指针

如果是为指针p申请一段内存,下面的代码能达到目的吗?

#include #include voidgetMemery(int*p) { /*申请1024个int大小*/ p=malloc(sizeof(int)*1024); if(NULL==p) { printf("mallocfailed\n"); p=NULL; } } intmain(void) { int*p=NULL; getMemery(p); printf("addressofpis%p\n",p); return0; }

通过前面的内容分析,肯定是达不到预期效果的。
运行结果:

addressofpis(nil)

这是为什么呢?我们还是利用前面所知来分析,由于传递给getMemory函数的参数都是一个副本,因此函数内的p也是外部p的一个副本,因此即便在函数内部,将p指向了一块新申请的内存,仍然不会改变外面p的值,即p还是指向NULL。

getMemory

如何修改呢?我们需要传入p的地址,即指向int类型指针的指针。

#include #include voidgetMemery(int**p) { /*申请1024个int大小*/ *p=malloc(sizeof(int)*1024); if(NULL==*p) { printf("mallocfailed\n"); *p=NULL; } } intmain(void) { int*p=NULL; getMemery(&p); printf("addressofpis%p\n",p); free(p); p=NULL; return0; }

运行结果如下:

addressofpis0x144f010

从运行结果可以看到,p的值被改变了,而不再是初始的NULL。

可配合下面的图进行理解:

getMemory

总结

本文总结如下:

函数的参数都是原数据的“副本”,因此在函数内无法改变原数据

函数中参数都是传值,传指针本质上也是传值

如果想要改变入参内容,则需要传该入参的地址(指针和引用都是类似的作用),通过解引用修改其指向的内容

以上结论不限于C语言

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144636
  • SWAP
    +关注

    关注

    0

    文章

    52

    浏览量

    13555
  • 函数
    +关注

    关注

    3

    文章

    4406

    浏览量

    66851
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    请问jtag和jlink什么区别啊?

    jtag和jlink什么区别啊?
    发表于 11-28 06:46

    物联网开发必备:四款低功耗蓝牙透模块参数全解析与应用实战

    物联网开发必备:四款低功耗蓝牙透模块参数全解析与应用实战 作为物联网设备的“无线神经末梢”,低功耗蓝牙(BLE)透模块的选择直接关系到产品的功耗、连接稳定性与开发周期。本文将从工程师视角,深度
    的头像 发表于 11-05 14:37 326次阅读

    微波雷达和毫米波雷达什么区别

    微波雷达和毫米波雷达什么区别 前言:不知道大家有没有发现,各种雷达模块的使用开始逐渐加入各种智能家居产品了,像人来灯亮,人走灯灭这种雷达感应的产品早几年就开始进入市场了,还有各种感应开关等产品
    的头像 发表于 10-30 16:56 1325次阅读
    微波雷达和毫米波雷达<b class='flag-5'>有</b><b class='flag-5'>什么区别</b>

    Re-Driver 和 Re-Timer 什么区别

    Re-Driver 和 Re-Timer 什么区别
    发表于 08-21 06:14

    科普|无线图和宽带自组网什么区别

    这两个设备到底哪些区别。其实无线图和宽带自组网设备在一些技术上是相通的,应用也有部分重叠,但是整体的技术原理和应用场景上上还是很大差别的。无线图
    的头像 发表于 08-15 17:44 727次阅读
    科普|无线图<b class='flag-5'>传</b>和宽带自组网<b class='flag-5'>有</b><b class='flag-5'>什么区别</b>?

    能光纤全面讲解

    能光纤,又称功率光纤,是一种具备特殊性能的光纤,在诸多领域发挥着关键作用。从严格意义上讲,凡是能够实现较高激光能量传输的光纤,均可被称为能光纤。其显著特点包括高功率传输能力、大芯径、良好的柔韧性
    的头像 发表于 08-12 09:06 448次阅读

    CY7C65214和CY7C65211/3/5什么区别

    CY7C65214 和其他 USB 串行桥接控制器之间什么区别:CY7C65211、CY7C65213 和 CY7
    发表于 05-29 06:49

    函数指针的六个常见应用场景

    函数指针在嵌入式开发中有着广泛的应用,它让代码更加灵活,减少冗余,提高可扩展性。很多时候,我们需要根据不同的情况动态调用不同的函数,而函数指针
    的头像 发表于 04-07 11:58 1136次阅读
    <b class='flag-5'>函数</b><b class='flag-5'>指针</b>的六个常见应用场景

    GD32与STM32什么区别

    电子发烧友网站提供《GD32与STM32什么区别.docx》资料免费下载
    发表于 04-03 17:27 0次下载

    怎样选择合适的数DTU?

    一款真正适配工业需求的数DTU?本文以济南有人物联网技术有限公司的明星产品USR-N720-C1为例,结合实际应用场景,解析数DTU的选型要点,助力企业实现高效、可靠的物联网部署。 一、数
    的头像 发表于 04-03 13:54 638次阅读

    关于STM32 CAN通信发送函数HAL_CAN_AddTxMessage()的最后一个参数填0和定义一个变量取地址的问题求解

    问题: 关于STM32 CAN通信 发送函数 HAL_CAN_AddTxMessage()的最后一个参数填0和定义一个变量取地址的问题,如果直接0,我实验发现 STM32F103
    发表于 03-11 08:22

    ATX主板和ITX主板什么区别

    在计算机硬件领域,主板是承载计算机核心组件的关键部件,其类型多样,性能也各有千秋。那么ATX主板和ITX主板什么区别呢,下面来介绍一下:
    的头像 发表于 03-03 08:47 1623次阅读

    私有云和公有云什么区别

    私有云和公有云在多个方面存在显著的区别,以下是具体的比较,主机推荐小编为您整理发布私有云和公有云什么区别
    的头像 发表于 02-20 10:38 1506次阅读

    AIGC和AI什么区别

    AIGC是AI在内容生成领域的一个特定应用方向,AI的技术发展为AIGC提供了基础和支撑。那么,AIGC和AI什么区别呢?下面,AI部落小编带您详细了解。
    的头像 发表于 02-20 10:33 1669次阅读

    C语言如何处理函数的返回

    当你在函数的最后写上 return 0 的时候,它是如何返回给调用函数的? 比如 test 函数,为了待会更好的看懂汇编代码,我写成了 return 1234。 处理函数的返回
    的头像 发表于 01-16 09:21 764次阅读