宋美英
(呂梁學(xué)院 離石師范分校,山西 呂梁 033000)
C語言作為一種結(jié)構(gòu)化程序設(shè)計語言,強調(diào)程序設(shè)計的風(fēng)格,提倡程序結(jié)構(gòu)的規(guī)范化,因此不可避免地需要使用函數(shù)調(diào)用,用函數(shù)作為構(gòu)件,可以開發(fā)出結(jié)構(gòu)清晰、功能齊全的大型程序.在C語言中,函數(shù)是程序的基本單位,一個C語言源程序可以由一個主函數(shù)或一個主函數(shù)和若干個其他函數(shù)組成,參數(shù)是實現(xiàn)函數(shù)間數(shù)據(jù)交換的主要通道.
在調(diào)用有參函數(shù)時,主調(diào)函數(shù)與被調(diào)函數(shù)之間有數(shù)據(jù)傳遞關(guān)系.定義函數(shù)時,出現(xiàn)在函數(shù)首部的參數(shù)稱為“形式參數(shù)”(簡稱“形參”).主調(diào)函數(shù)中,調(diào)用函數(shù)時,函數(shù)名后面圓括號中所使用的參數(shù)稱為“實際參數(shù)”(簡稱“實參”).實參與形參應(yīng)保持個數(shù)一致、類型相同或兼容.
形參與實參占用不同的存儲單元.作為局部變量,形參只在本函數(shù)體內(nèi)有效.在未發(fā)生函數(shù)調(diào)用時,形參并不占用內(nèi)存中的存儲單元.只有在發(fā)生函數(shù)調(diào)用時,才為形參分配內(nèi)存單元,同時將實參的值傳遞給被調(diào)函數(shù)的形參.在函數(shù)調(diào)用結(jié)束后,釋放形參所占的內(nèi)存單元.
在C語言中,參數(shù)間的數(shù)據(jù)傳遞是單向的,即數(shù)據(jù)只能由實參傳給形參,而不能由形參傳回給實參.根據(jù)參數(shù)類型的不同,可以將參數(shù)間的數(shù)據(jù)傳遞方式分為“值傳遞”和“地址傳遞”兩種.下面通過幾個交換問題的具體執(zhí)行過程探討C語言中函數(shù)參數(shù)的傳遞問題.
當(dāng)參數(shù)為普通類型時,形參變量與實參變量占用不同的內(nèi)存空間,形參的改變并不能影響所對應(yīng)的實參的值.
[例1] void swap1(int x, int y)
{ int t;
t=x; x=y; y=t;
}
main( )
{ int a=5, b=9;
swap1(a,b);
printf(“a=%d,b=%d ”,a,b);
}
程序運行結(jié)果為:
a=5,b=9
由輸出結(jié)果可以看出,實參變量a、b的值并沒有發(fā)生交換.例1中各變量值的變化情況如圖1所示.
圖1 參數(shù)為普通類型時各變量變化情況
發(fā)生函數(shù)調(diào)用時,為形參x和y分配內(nèi)存空間,同時實參把自己的值復(fù)制一份依次傳遞給形參,形參x和y分別得到5和9,然后形參使用得到的值參與被調(diào)函數(shù)中的運算.事實上,在值傳遞的過程中,有一項操作隱含在被調(diào)函數(shù)中.這個隱含操作確實存在,如果把它顯式地寫出來,可得被調(diào)函數(shù)如下:
void swap1(int x, int y)
{ int t;
x=a; y=b; //執(zhí)行被調(diào)函數(shù)時的隱含操作
t=x; x=y; y=t;
}
現(xiàn)在問題變得清晰起來,發(fā)生函數(shù)調(diào)用時,只是隱含地把實參a、b的值通過賦值的方式傳遞給了形參x、y,形參并沒有代替實參,修改形參也就并不意味著修改了實參.因此,在被調(diào)函數(shù)中交換了形參變量x和y的值,函數(shù)調(diào)用結(jié)束時,釋放形參所占用的存儲空間并返回主函數(shù),此時形參x、y不復(fù)存在,而實參a和b的值并沒有發(fā)生變化.
當(dāng)實參為變量的地址、指針變量或數(shù)組名等實質(zhì)上表示地址的形式時,形參應(yīng)使用指針變量或數(shù)組名.發(fā)生函數(shù)調(diào)用時,由形參接收實參中的地址值,此時,形參與實參指向同一段存儲單元.如果在被調(diào)函數(shù)中修改形參指針?biāo)赶虻牡刂分械膬?nèi)容,那么主調(diào)函數(shù)中變量的值也會發(fā)生同步改變.
[例2] void swap2(int *x, int *y)
{ int t;
t=*x; *x=*y; *y=t;
}
main( )
{ int a=5, b=9;
int *p1=&a, *p2=&b;
swap2(p1, p2);
printf(“a=%d, b=%d ”,a,b);
}
程序運行結(jié)果為:
a=9,b=5
由輸出結(jié)果可以看出,主函數(shù)中的變量a、b的值發(fā)生了交換.例2中各變量值的變化情況如圖2所示.
圖2 參數(shù)為指針類型且交換指針?biāo)竷?nèi)容時各變量變化情況
主函數(shù)中,實參指針變量p1和p2分別存放a、b的地址,發(fā)生函數(shù)調(diào)用時,傳遞的并不是變量的值,而是變量的地址,即將a、b的地址傳給了形參指針x和y,這就是所謂的“地址傳遞”.其實它與值傳遞相同,同樣在被調(diào)函數(shù)中有一項隱含操作如下:
void swap2(int *x, int *y)
{ int t;
x=&a; y=&b; //執(zhí)行被調(diào)函數(shù)時的隱含操作
t=*x; *x=*y; *y=t;
}
由隱含的賦值操作可以看出,形參指針x和y分別存放a、b變量的地址值.接下來執(zhí)行被調(diào)函數(shù)時,對*x和*y的操作也就是對a、b變量本身的操作.因此,交換了*x和*y的值,也就是交換了形參指針變量所指向地址中的內(nèi)容.函數(shù)調(diào)用結(jié)束返回主函數(shù)時,釋放形參所占的單元,不存在了的只是形參指針變量x和y,它們原來所指向單元中修改過的值被保留下來.本例主函數(shù)中的變量實現(xiàn)交換,這只是利用了指針對變量的間接訪問方式,使用指針變量作參數(shù),從而實現(xiàn)對主調(diào)函數(shù)中變量值的修改,這并不是由于數(shù)據(jù)從形參傳回給了實參,實參向形參的單向數(shù)據(jù)傳遞性是不變的.因此,有的文獻將地址傳遞描述為“雙向傳遞”是不妥當(dāng)?shù)?
[例3] void swap3(int *x, int *y)
{ int *t;
t=x; x=y; y=t;
}
main( )
{ int a=5,b=9;
int *p1=&a,*p2=&b;
swap3(p1,p2);
printf(“a=%d,b=%d ”,a,b);
}
程序運行結(jié)果為:
a=5,b=9
由輸出結(jié)果可知,使用指針變量作參數(shù),也不一定能夠改變主調(diào)函數(shù)中變量的值.這是因為雖然同例2相同,本例中的參數(shù)傳遞方式依然是地址傳遞,但函數(shù)swap3( )只是交換了x和y中所存放的地址,即改變了兩個指針的指向,并沒有改變指針?biāo)竼卧械闹?,因此主函?shù)中兩個變量的值并沒有被交換.例3中各變量值的變化情況如圖3所示.
圖3 參數(shù)為指針類型且交換指針變量本身時各變量變化情況
C語言中,一般將函數(shù)參數(shù)的傳遞方式分為值傳遞和地址傳遞兩種,這只是根據(jù)參數(shù)類型的不同而進行的一種分類.值傳遞指參數(shù)為普通類型時的參數(shù)傳遞,而地址傳遞一般指參數(shù)的實質(zhì)是地址類
的參數(shù)傳遞.事實上,無論參數(shù)的類型如何,參數(shù)間的數(shù)據(jù)傳遞方式都是單向的,即只能由實參傳遞給形參,值傳遞和地址傳遞的區(qū)別僅在于傳遞的數(shù)據(jù)類型不同.
參考文獻:
[1]董漢麗.C語言程序設(shè)計[M].大連:大連理工大學(xué)出版社,2009.
[2]譚浩強.C程序設(shè)計(第四版)[M].北京:清化大學(xué)出版社,2010.
[3]董鑫正.C語言教學(xué)中函數(shù)參數(shù)傳遞問題的探討[J].電腦知識與技術(shù),2012(7).
[4]馬新.C語言函數(shù)間參數(shù)傳遞機制的探討[J].白城師范學(xué)院學(xué)報,2008(6).