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

前言
函数传参有三种传参方式:传值、传址、传引用。
我们可能听过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语言

最强机皇依然是小米6,小米6价格将还是1999,对此雷军发话了
基于PXA272微控制器的WINCE文件系统的实现及在手持移动终端上的应用
PTC自恢复保险丝选型指南
SM15133EK 恒流LED驱动芯片 明微电子
采用JN5139模块的无线网络技术实现船艇消防安全监测系统的设计
C语言函数参数关于传值和传指针有什么区别?
三星S6edge+外观设计解读
新思考:以“新物联”提速新基建
文心一言APP与澳门签署战略合作!打造“AI+旅游”澳门样本
电子芯闻早报:中国第一芯将浮出水面 小米VR今日发布
防爆五参数气象站的技术参数介绍
电能管理系统的设计及应用,它的优势是什么
三星Note8将如期而至 配4K显示屏+最新Bixby语音助手
微芯片抑制人的暴饮暴食
华为和三星在5G网速领域的较量
如何从MySQL中提取数据并增加换手率指标进行回测
智能电网中,为什么要用电能质量分析装置?
20万吨磷酸铁锂正极材料项目投产!
镭豆2+智能空气质量检测仪评测 第一款入驻苹果店的PM2.5检测仪
米家智能除菌加湿器发布 售价249元