剛開始學習模塊化程序設計時,估計大家都被形參和實參搞迷糊過,尤其是遇到形參名和實參名一樣時,更加暈頭轉向,出現一種“是誰把值傳給了我,而我又傳給了誰”的疑惑。我也有過類似的迷茫,更是被其他初學的同學問過很多次。想了好久還是決定整理一下,把它寫成博客供更多人學習,而且是通過調試這一種直觀的方式。下面進入本次的正題,不足之處請多多包涵,歡迎各位大佬在評論區補充有關知識。
首先我們來看一下二者的區別和特點:
一、形參和實參區別:
(1)函數定義方式不同
形參出現在函數定義中,在整個函數體內都可以使用, 離開該函數則不能使用。
實參出現在主調函數中,進入被調函數后,實參變量也不能使用。
(2)使用原理不同
函數的形參列於函數聲明中,在函數定義的函數體內使用。當函數調用時,形參(任何種類的)是一類將被填充的空白或是占位符。
實參是用來填充形參的。當函數被調用時,形參列在函數名后面的括號里。執行函數調用時,實參被傳遞給形參。
(3)傳值調用和引用調用不同
傳值調用和引用調用指的是用於參數傳遞過程中的一種機制。傳值調用中,只使用了實參的值。
傳值調用機制里,形參是一個局部變量,其初始值為相應實參的值。在引用調用機制里,將實參的地址傳遞給形參,從表面上看是以實參變量取代形參,因此任何發生在形參上的改變實際上都發生在實參變量上。
二、形參和實參的特點:
(1)形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。函數調用結束返回主調用函數后則不能再使用該形參變量。
(2)實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。因此應預先用賦值、輸入等辦法使參數獲得確定值。
(3)實參和形參在數量上,類型上、順序上應嚴格一致,否則就會發生類型不匹配的錯誤。
然后再來看看這次用到的源代碼:
1 #include<stdio.h> 2 3 void swap1(int x, int y) { //傳值調用 4 int temp = x; 5 x = y; 6 y = temp; 7 } 8 9 void swap2(int *x, int *y) { //引用調用 10 int temp = *x; 11 *x = *y; 12 *y = temp; 13 } 14 15 void init1(int x[]) { //引用調用 16 int i; 17 for(i = 0; i < 10; ++i) 18 x[i] = i; 19 } 20 21 int main() { 22 int a = 1, b = 5, i; 23 int c[10]; 24 int *p, *q; 25 p = &a; 26 q = &b; 27 28 swap1(a, b); 29 printf("經swap1函數處理后a = %d, b = %d\n", a, b); 30 31 swap2(p, q); 32 printf("經swap2函數處理后a = %d, b = %d\n", a, b); 33 34 init1(c); 35 printf("使用init函數對數組c賦值后結果如下:\n"); 36 for(i = 0; i < 10; ++i) 37 printf("%d ", c[i]); 38 39 return 0; 40 }
然后是具體的調試情況:
使用Dev-C++第一次調試之前需要先進行配置,首先打開編譯選項:
之后選擇“代碼生成/優化”這一項,接着選擇“連接器”一項,把其中的“產生調試信息”一項的NO改為YES,然后點擊確認就可以啦,具體情況如下:
配置完畢,我們首先將斷點設置在swap1函數處(點擊代碼行所在的序號即可設置斷點),如圖:
然后開始進行調試(注意:調試前需要先對源碼進行編譯),操作及介紹如下:
其中“添加查看”代表添加要觀察的變量,“下一步”即在本函數內執行下一步,如果想查看它調用的函數的執行情況,可在執行到調用函數這一步時選擇“單步進入”(本例中,剛開始就要點擊單步進入,觀察函數swap1的內部執行情況),其他選項同其它們的字面意思一樣。
本次觀察對象為變量a,b,x,y的值以及他們的地址,具體的添加操作如下(點擊右下角添加查看后輸入要查看的變量名,然后回車確認):
待查看的變量會顯示在左上角,本次查看的變量如圖(Execute to evaluate代表變量的值還無法知曉):
執行單步進入后結果如下:
不難發現,傳值調用的情況下,x,y只是復制了a,b的值。它們在內存中的位置(地址)是完全不同的,所以傳值調用情況下形參的值發生變化並不影響實參,輸出結果也證實了我們的結論:a,b的值並沒有發生變化
同理,我們來通過調試來觀察swap2函數的內部執行情況,本次觀察p,q和x,y的值:
代碼中,p和q為int類型的指針,分別指向a和b的地址。從上圖可以看到引用調用的情況下我們傳遞的地址被x和y復制,所以我們對x和y進行的操作都會反映到原來的變量a和b上,輸出結果也能證明我們的猜測:
上面的例子都是簡單的單個變量傳參,那么數組作為參數時是如何傳遞的呢?還是來調試一下:
結果很明顯:數組作為參數傳遞時,也是引用調用方式,傳的是地址。所以把數組作為參數傳遞后,數組在函數內發生的變化都會被保留下來。所以各位在設計函數時務必注意執行完某個函數需不需要實參變量發生變化,根據情況選擇傳值調用還是引用調用方式。講的不足的地方還請見諒,歡迎各位批評指正!