您好,登錄后才能下訂單哦!
前言
我們可能聽(tīng)過(guò)C語(yǔ)言中的傳值和傳指針,在其他語(yǔ)言中,也有傳引用一說(shuō),那么他們到底有什么區(qū)別呢?如果你還不能準(zhǔn)確地分辨,就該好好了解一下了。
傳值
我們?cè)诔鯇W(xué)C語(yǔ)言的時(shí)候就被老師教過(guò),下面的方式是無(wú)法交換a和b的值的:
#include<stdio.h> void 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; }
運(yùn)行結(jié)果如下:
before swap:a = 10,b = 20
internal swap a = 20,b = 10
after swap:a = 10,b = 20
可以看到,a和b的值最終并沒(méi)有被交換。開(kāi)始時(shí)a,b的值為10,20,而最終還是同樣的值。
為什么呢?因?yàn)楹瘮?shù)參數(shù)在傳遞的時(shí)候,都是傳原數(shù)據(jù)的副本,也就是說(shuō),swap內(nèi)部使用的a和b只是最初始a和b的一個(gè)副本而已,所以無(wú)論在swap函數(shù)內(nèi)部對(duì)a和b做任何改變,都不會(huì)影響初始的a和b的值。
正因如此,我們常常被告知,不要把直接把結(jié)構(gòu)體直接作為參數(shù),這樣效率會(huì)很低。由于結(jié)構(gòu)體本身占用字節(jié)數(shù)較大,如果直接作為參數(shù),那么將會(huì)產(chǎn)生一個(gè)較大的”副本“,如此一來(lái),效率也就很低了。
我們?cè)俳Y(jié)合下面的圖來(lái)理解:
首先圖中方框中的上部分a和b代表了main函數(shù)中的a和b,即原始數(shù)據(jù),而方框中的下部分a和b代表了函數(shù)的參數(shù)a和b,即原始數(shù)據(jù)的“副本”。(后面的圖都是如此,上部分代表原始值,下部分代表函數(shù)參數(shù)值)。
調(diào)用swap函數(shù)前后的情形如下:
由于在swap中永遠(yuǎn)只是對(duì)a和b的副本進(jìn)行操作,因此完全不影響原始的a和b的值。最終也不可能達(dá)到交換a和b的值的目的。
傳指針
那么為解決上面的問(wèn)題,我們知道,需要傳指針。其代碼如下:
#include<stdio.h> void 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; }
運(yùn)行結(jié)果:
before swap:a = 10,b = 20
swap a = 20,b = 10
after swap:a = 20,b = 10
可以看到在這種情況下,a,b的值才是真正交換了。
為什么又有傳值,又有傳指針
看到這里,不知道你是否會(huì)疑惑,為什么給函數(shù)傳遞參數(shù)的時(shí)候,一會(huì)是傳值,一會(huì)是傳指針呢?為什么傳指針就能改變參數(shù)的值呢?實(shí)際上,C語(yǔ)言里,參數(shù)傳遞都是值傳遞!也就是說(shuō),你認(rèn)為的傳指針也是傳值,只不過(guò)它的值是指針類型罷了。
我們?cè)偻ㄟ^(guò)圖來(lái)理解前面為什么傳指針就可以交換a,b的值:
從圖中可以看出,雖然傳遞給函數(shù)的是指向a和b的指針的副本,但是它的副本同樣也是指向a和b,因此雖然不能改變指針的指向,但是能改變參數(shù)a和b指向的內(nèi)容,即改變?cè)糰和b的值。
再看傳指針
如果是為指針p申請(qǐng)一段內(nèi)存,下面的代碼能達(dá)到目的嗎?
#include<stdio.h> #include<stdlib.h> void getMemery(int *p) { /*申請(qǐng)1024個(gè)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; }
通過(guò)前面的內(nèi)容分析,肯定是達(dá)不到預(yù)期效果的。
運(yùn)行結(jié)果:
address of p is (nil)
這是為什么呢?我們還是利用前面所知來(lái)分析,由于傳遞給getMemory函數(shù)的參數(shù)都是一個(gè)副本,因此函數(shù)內(nèi)的p也是外部p的一個(gè)副本,因此即便在函數(shù)內(nèi)部,將p指向了一塊新申請(qǐng)的內(nèi)存,仍然不會(huì)改變外面p的值,即p還是指向NULL。
如何修改呢?我們需要傳入p的地址,即指向int類型指針的指針。
#include<stdio.h> #include<stdlib.h> void getMemery(int **p) { /*申請(qǐng)1024個(gè)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; }
運(yùn)行結(jié)果如下:
address of p is 0x144f010
從運(yùn)行結(jié)果可以看到,p的值被改變了。
可配合下面的圖進(jìn)行理解:
總結(jié)
本文總結(jié)如下:
思考
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)億速云的支持。
本文作者: 守望
本文鏈接: https://www.yanbinghu.com/2019/06/20/53981.html
版權(quán)聲明: 本文為原創(chuàng)文章,版權(quán)歸守望所有,并采用 CC BY-NC-SA 3.0 許可協(xié)議。轉(zhuǎn)載請(qǐng)聯(lián)系本人!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。