C语言中传值与传指针的区别是什么
创始人
2024-12-21 19:03:10
0次

前言

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

传值

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

#includevoid swap(int a,int b){ int temp = a; a = b; b = temp; printf("swap a = %d,b = %d\n",a,b);}int main(void){ int a = 10; int b = 20; printf("before swap:a = %d,b = %d\n",a,b); swap(a,b); printf("after swap:a = %d,b = %d\n",a,b); return 0;}

运行结果如下:

before swap:a = 10,b = 20 internal swap a = 20,b = 10 after swap: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中永远只是对a和b的副本进行操作,因此完全不影响原始的a和b的值。最终也不可能达到交换a和b的值的目的。

传指针

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

#includevoid swap(int *a,int *b){ int temp = *a; *a = *b; *b = temp; printf("swap a = %d,b = %d\n",*a,*b);}int main(void){ int a = 10; int b = 20; printf("before swap:a = %d,b = %d\n",a,b); swap(&a,&b); printf("after swap:a = %d,b = %d\n",a,b); return 0;}

运行结果:

before swap:a = 10,b = 20 swap a = 20,b = 10 after swap:a = 20,b = 10

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

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

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

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

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

再看传指针

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

#include#includevoid getMemery(int *p){ /*申请1024个int大小*/ p = malloc(sizeof(int)*1024); if(NULL == p) { printf("malloc failed\n"); p = NULL; }}int main(void){ int *p = NULL; getMemery(p); printf("address of p is %p\n",p); return 0;}

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

运行结果:

address of p is (nil)

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

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

#include#includevoid getMemery(int **p){ /*申请1024个int大小*/ *p = malloc(sizeof(int)*1024); if(NULL == *p) { printf("malloc failed\n"); *p = NULL; }}int main(void){ int *p = NULL; getMemery(&p); printf("address of p is %p\n",p); free(p); p = NULL; return 0;}

运行结果如下:

address of p is 0x144f010

从运行结果可以看到,p的值被改变了。

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

总结

本文总结如下:

函数的形参都是原数据的“副本”,因此在函数内无法改变原数据  函数中参数都是传值,传指针本质上也是传值  如果想要改变入参内容,则需要传该入参的地址(指针和引用都是类似的作用),通过解引用修改其指向的内容  以上结论不限于C语言

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...