就是一個函數的輸入參數是一個指針,該函數需要改變該指針指向的地址,如: 現在有一個全局數組b,現在需要編寫一個函數 輸入參數是一個指針a,需要通過該函數將該指針a指向數組b,即:
intb[3]={1,2,3};
voidfcn(參數);
voidmain()
{
int*a;
fcn(輸入參數a)
}
執行完fcn后,使參數的地址改變,這個功能怎么來實現呢?
首先說明結論:使用二級指針。
為了更好的理解這個問題,我們首先來學習一下指針最經典的例子,交換兩個數來說明函數的形參和實參之間的關系。
首先來探究以下實參和形參的關系是怎樣的。
形參為普通變量類型;
voidtest1(inta,intb)
{
printf(">>formaladdra:%d,formaladdrb:%d
",&a,&b);//打印形參地址
printf(">>formalvaluea:%d,formalvalueb:%d
",a,b);//打印形參值
}
intmain()
{
inta=1,b=2;
printf(">>actualaddra:%d,actualaddrb:%d
",&a,&b);
printf(">>actualvaluea:%d,actualvalueb:%d
",a,b);
test1(a,b);
return0;
}
下面是執行結果:
>>actualaddra:6422300,actualaddrb:6422296
>>actualvaluea:1,actualvalueb:2
>>formaladdra:6422272,formaladdrb:6422276
>>formalvaluea:1,formalvalueb:2
可以看到形參和實參的值雖然相同,但是他們的地址卻不相同,所以函數在被調用的時候傳入的參數(實參)實際上是被復制到另一個地址(形參地址)中去了,函數中對傳入參數的操作實際上是對形參地址中的數進行操作,而與實參無關。所以下面的函數不能實現交換兩個數的功能。
voidswap_1(inta,intb)
{
inttemp;
temp=a;
a=b;
b=temp;
printf(">>formaladdra:%d,formaladdrb:%d
",&a,&b);
printf(">>formalvaluea:%d,formalvalueb:%d
",a,b);
}
intmain()
{
int a = 1, b = 2;
swap_1(a,b);
printf(">>actualaddra:%d,actualaddrb:%d
",&a,&b);
printf(">>actualvaluea:%d,actualvalueb:%d
",a,b);
return0;
}
輸出如下:
>>formaladdra:6422272,formaladdrb:6422276
>>formalvaluea:2,formalvalueb:1
>>actualaddra:6422300,actualaddrb:6422296
>>actualvaluea:1,actualvalueb:2
可以看到在swap_1函數中a,b兩個數的值是被調換了的,但是函數中的a,b的地址和主函數中a,b的地址根本不是同一個,主函數中a,b還是原來的數,所以這個函數起不到交換兩個數功能。
既然形參和實參的關系是地址不同而值相同那么我們將實參的地址當作參數傳給形參,然后在函數中對形參所指向的地址中的值(該地址就是實參的地址)進行改變是否就可以完成兩個數的交換了?
OK!下面我們來編寫函數測試以下:
voidswap_2(int*a,int*b)
{
inttemp;
printf(">>formaladdra:%d,formaladdrb:%d
",&a,&b);//打印形參地址
printf(">>formalvaluea:%d,formalvalueb:%d
",a,b);//打印形參的值
printf(">>formaladdrvaluea:%d,formaladdrvalueb:%d
",*a,*b);//打印以形參值為地址的值
temp=*a;
*a=*b;
*b=temp;
printf(">>formaladdra:%d,formaladdrb:%d
",&a,&b);
printf(">>formalvaluea:%d,formalvalueb:%d
",a,b);
printf(">>formaladdrvaluea:%d,formaladdrvalueb:%d
",*a,*b);
}
intmain()
{
inta=1,b=2;
swap_2(&a,&b);
printf(">>actualaddra:%d,actualaddrb:%d
",&a,&b);
printf(">>actualvaluea:%d,actualvalueb:%d
",a,b);
return0;
}
結果如下:
>>formaladdra:6422272,formaladdrb:6422276
>>formalvaluea:6422300,formalvalueb:6422296
>>formaladdrvaluea:1,formaladdrvalueb:2
>>formaladdra:6422272,formaladdrb:6422276
>>formalvaluea:6422300,formalvalueb:6422296
>>formaladdrvaluea:2,formaladdrvalueb:1
>>actualaddra:6422300,actualaddrb:6422296
>>actualvaluea:2,actualvalueb:1
從結果可以看出,這個函數可以交換輸入參數的值。下面我們來分析一下為什么這個函數能夠實現交換功能。
以變量a為例,首先,從結果的第一行可以看出,傳入函數的參數是地址(即實參a的地址:6420300),這個地址作為一個值存放在形參a(地址:6422272)中,然后定義一個int型變量來存放地址6422272(形參a的地址)中的值6422300(實參a的地址),然后將指向6422296(實參b的地址)地址中的值 賦給 指向6422300(實參a的地址),開始地址6422300地址中的值為2,現在該地址的值變為1,同理,在執行函數之后地址6422296中的值變為1,從而實現了兩個數的交換。
在這個過程中,是函數調用a,b兩個值的地址,并在函數中改變這兩地址中的值。與上一個函數的本質區別就是:上一個函數swap1只是將a,b的值給復制到兩個新的地址當中,并改變新的地址中的值,與a,b地址無關。而swap_2則是直接操作a,b地址中的值,進而可以實現交換兩個數的功能。
注意:實參和形參是在兩個不同地址,雖然起的名字是一樣的,當然這個名字可以自己隨意起。為了更加清楚的說明實參和形參是兩個東西,下面我將形參的變量名給改一下:
voidswap_2(int*formal_a,int*formal_b)
{
inttemp;
printf(">>formaladdra:%d,formaladdrb:%d
",&a,&b);
printf(">>formalvaluea:%d,formalvalueb:%d
",a,b);
printf(">>formaladdrvaluea:%d,formaladdrvalueb:%d
",*a,*b);
temp=*formal_a;
*formal_a=*formal_b;
*formal_b=temp;
printf(">>formaladdra:%d,formaladdrb:%d
",&a,&b);
printf(">>formalvaluea:%d,formalvalueb:%d
",a,b);
printf(">>formaladdrvaluea:%d,formaladdrvalueb:%d
",*a,*b);
}
intmain()
{
inta=1,b=2;
swap_2(&a,&b);
printf(">>actualaddra:%d,actualaddrb:%d
",&a,&b);
printf(">>actualvaluea:%d,actualvalueb:%d
",a,b);
return0;
}
結果如下:
>>formaladdra:6422272,formaladdrb:6422276
>>formalvaluea:6422300,formalvalueb:6422296
>>formaladdrvaluea:1,formaladdrvalueb:2
>>formaladdra:6422272,formaladdrb:6422276
>>formalvaluea:6422300,formalvalueb:6422296
>>formaladdrvaluea:2,formaladdrvalueb:1
>>actualaddra:6422300,actualaddrb:6422296
>>actualvaluea:2,actualvalueb:1
和之前的結果一樣,可以知道,函數在執行的時候其實是不管你名字怎么起的,而是關心地址,而你起的名字實際也只是那個地址的代號而已。
通過上面的例子已經清楚了函數的形參與實參的區別,那么現在就來解決文章開頭提出的問題
如何通過函數改變一個傳入指針作為實參的地址,其實在理解上面的關于函數的形參和實參就非常容易懂了。
首先我們來看下面一個例子
intb[3]={1,2,3};
voidfcn(int**a)
{
*a=b;
}
intmain()
{
unsignedinti=0;
int*a;
for(i=0;i<3;i++)
?????{
?????????printf(">>%d
",a[i]);
}
fcn(&a);
for(i=0;i<3;i++)
?????{
?????????printf(">>%d
",a[i]);
}
}
函數輸出為:
>>0
>>-1
>>4194304
>>1
>>2
>>3
主函數中,我們定義了一個指針a,并且沒有初始化它,之后我們是不能夠直接對它指向的地址進行賦值,因為現在它的地址是隨機的,對該地址進行操作后有可能會導致程序崩潰。我們想要用它就只能夠對它自己的值也就是它所指向的地址進行操作。函數fcn通過形參來改變輸入實參的值是怎么做到的呢?
首先看函數的形參(int **a)
,表示什么意思呢?就是說傳入的一個二級指針,指向指針的指針,這又是什么意思呢?比如你有一張藏寶圖,它說寶藏在a地,你到a地之后也只得到一張藏寶圖,該藏寶圖說寶藏在b地,你只有到達b地才能夠得到寶藏。這就是一個二級指針,第一個指向的地址是a,a的內容也是一個指針,指向b,b地址下才是真正的內容。
我們在主函數中定義了一個指針a,讓它傳入函數fcn,我們分析一下這個過程:
函數開辟一個形參的地址,該地址中的內容為指向傳入參數地址的值,那么函數中我們將數組b的首地址賦給該地址,也就是將實參的地址更改成了數組b的首地址。
文章確實太繞了,個人覺得最主要的點就是弄清楚指針與地址以及該地址的值的關系,還有就是形參與實參的關系。
-
C語言
+關注
關注
180文章
7599瀏覽量
136218 -
函數
+關注
關注
3文章
4307瀏覽量
62433 -
指針
+關注
關注
1文章
480瀏覽量
70511
原文標題:C語言指針作為形參如何改變其指向的地址?
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論