函式的引數和函式呼叫

2021-06-29 03:15:06 字數 4899 閱讀 6490

1 函式的引數

在呼叫函式時,大多數情況下主調函式和被調函式之間存在著資料傳遞關係。於是就用到了形式引數和實際引數,簡稱形參和實參。在定義函式時函式名後面括號中的變數稱為「形參」,在主調函式(一般為main)呼叫乙個函式時,函式名後面括號中的引數(可以是乙個表示式)稱為「實參」。

例如:

void func(int x,int y)

/*x、y為形參*/

void main()

關於形參和實參的說明:

(1)在定義函式中指定的形參在未出現函式呼叫時,它們並不占用記憶體中的儲存單元。只有在發生函式呼叫時,形參才被分配到記憶體單元。在呼叫結束後,形參所占用的記憶體單元也被釋放。

(2)實參可以使常量、變數或者表示式,但要求它們必須有確定的值。在呼叫時將實參的值賦給形參(如果形參是陣列名,則傳遞的是陣列的首位址而不是陣列的值)

(3)在被定義的函式中,必須指定形參的型別

(4)實參與形參的型別必須相同或賦值相容

(5)c語言規定,實參變數對形參變數的資料傳遞是「值傳遞」,即單向傳遞,只由實參傳給形參,而不能由形參傳回來給實參。在呼叫函式時,給形參分配儲存單元並將實參對應的值傳遞給形參(實際上是對實參的拷貝),呼叫結束後,形參單元被釋放,實參單元容保留並維持原值。因此,在執行乙個被呼叫函式時,形參的值如果發生改變,並不會改變主調函式實參的值。

2 陣列作為函式引數

陣列名作為形參或實參,傳遞的是陣列的首位址。另外,陣列元素可作為函式的實參

注意:(1)用陣列名作為函式引數,應該在主調函式和被呼叫函式分別定義陣列,不能只在一方定義

(2)實參陣列與形引數組型別應一致,如不一致,結果將出錯。

(3)在被呼叫函式中宣告形引數組的大小是不起作用的,在實際中c編譯對形引數組的大小是不做檢查的,只是將實參陣列的首位址傳給形引數組。

(4)形引數組也可不指定大小,在定義陣列時在陣列後面跟上乙個空的方括號。有時候。為了在被呼叫函式中處理陣列元素的需要,可以另設乙個引數,傳遞需要處理的陣列元素的個數。

(5)用陣列名作為函式實參時,不是把陣列元素的值傳遞給形參,而是把實參陣列的起始位址傳遞給形引數組,這樣兩個陣列共同占用一段記憶體單元。由此可以看出,形引數組中各元素的值如發生變化會使實參陣列元素的值同時發生變化。

(6)形參陣列名在c編譯時被當作指標變數來處理

例如:形引數組:f(int array,int n)

在編譯時將array按指標變數處理,相當於:f(int *array,int n)

(7)實參陣列名代表乙個固定的位址,或者說是指標型常量,而形引數組並不是乙個固定的位址值。作為指標變數,在函式呼叫開始時,它的值等於實參陣列起始位址,但在被呼叫函式執行期間,它可以被再賦值

3 用多維陣列名作函式引數

可以用多維陣列名作為實參和形參,在被呼叫函式中對形引數組定義時可以制定每一維的大小,也可以省略第一維的大**明,c編譯不檢查第一維陣列的大小

注意:(1)不能把第二維以及其他高維的大**明忽略

(2)在第二維大小相同的前提下,形引數組的第一維可以與實參陣列不同

例如:實參陣列定義為:int score[5][10]

而形引數組定義為:int array[3][10]或者int array[8][10];

4 指標變數作為函式引數

指標變數可以作實參也可以做形參。

為了使在函式中改變了的變數之能被函式main所用,不能採取將要改變的普通變數作為引數的辦法,而應該用指標變數為函式引數,在函式執行過程中使指標變數所指向的變數值發生改變,函式呼叫結束後這些變數值的變化仍然保留下來。

如果想通過函式呼叫得到n個要改變的值,可以:

(1)在主調函式中設n個變數,用n個指標變數指向它們

(2)將指標變數作為實參,把n個變數的位址傳給所呼叫的函式的形參

(3)通過形參指標變數,改變這n個變數的值

(4)主調函式中就可以使用這些改變了值的變數,在這一過程中,n個指標的值是固定不變得,但其對應的變數的值是改變的

5 如果由乙個實參陣列,想在函式中改變此陣列元素的值,實參與形參的對應關係有以下4種情況:

(1)形參和實參都用陣列名,如:

main()           |f(int x,int n)          

}                |

由於形參陣列名接收了實參陣列首元素的位址,因此可以認為在函式呼叫期間形引數組與實參陣列公用一段記憶體單元,這種形式比較好理解。

(2)實參用陣列名,形參用指標變數

main()           |f(int *x,int n)

....             |

}                |

實參a為陣列名,形參x為指向整型變數的指標變數,函式開始執行時,x指向a[0],即x=&a[0]。通過x值的改變,可以指向a陣列的任一元素。

(3)實參形參都用指標變數

main()           |f(int *x,int n)

f(p,10);         | 

...              |

}                |

實參p和形參x都是指標變數。先使實參指標變數p指向陣列a,p的值是&a[0]。然後將p的值傳給形參指標變數x,x的初始值也是&a[0]。通過x值的改變可以使x指向陣列a的任一元素。

(4)實參為指標變數,形參為陣列名

main()           |f(int x,int n)

f(p,10);         |

....             |

}                |

實參p為指標變數,它使指標變數p指向a[0],即p=a或者p=&a[0],形參為陣列名x.在編譯過程中將x做為指標變數處理。實際上這和第一種方法是相同的

注意:如果使用指標變數作為實參,必須先使指標變數有確定的值,指向乙個已定義的單元。

6 關於陣列作為函式引數的按值傳遞和按位址傳遞

在把陣列作為引數傳遞給函式時,有值傳遞(by value)和位址傳遞(by reference)兩種方式。在值傳遞方式中,在說明和定義函式時,要在陣列引數的尾部加上一對方括號(),呼叫函式時只需將陣列的位址(即陣列名)傳遞給函式。例如,在下例中陣列x是通過值傳遞方式傳遞給byval_func()函式的:

# includevoidbyval_func(int);       /*the  byval_func()  function is passed an integer array by value * / 

void main (void);

void main (void)

/* the byval_function receives an integer array by value. * /

void byval_func(int i)

在上例中,定義了乙個名為x的陣列,並對它的10個元素賦了初值。函式byval_func()的說明如下所示:

intbyval_func(int );

引數int告訴編譯程式byval_func()函式只有乙個引數,即乙個由int型別值組成的陣列。在呼叫byval_func()函式時,只需將陣列的位址傳遞給該函式,即:

byval_func(x);

在值傳遞方式中,陣列x將被複製乙份,複製所得的陣列將被存放在棧中,然後由byval_func()函式接收並列印出來。由於傳遞給byal_func()函式的是初始陣列的乙份拷貝,因此在byval_func()函式內部修改傳遞過來的陣列對初始陣列沒有任何影響。

值傳遞方式的開銷是非常大的,其原因有這樣幾點:第一,需要完整地複製初始陣列並將這份拷貝存放到棧中,這將耗費相當可觀的執行時間,因而值傳遞方式的效率比較低;第二,初始陣列的拷貝需要占用額外的記憶體空間(棧中的記憶體);第三,編譯程式需要專門產生一部分用來複製初始陣列的**,這將使程式變大。

位址傳遞方式克服了值傳遞方式的缺點,是一種更好的方式。在位址傳遞方式中,傳遞給函式的是指向初始陣列的指標,不用複製初始陣列,因此程式變得精練和高效,並且也節省了棧中的記憶體空間。在位址傳遞方式中,只需在函式原型中將函式的引數說明為指向陣列元素資料型別的乙個指標。請看下例:

# include

void conat_func(const int* ); 

void main (void);

void main(void)

/*the  const_function receives an integer array by reference. 

notice that the pointer i» declared aa const, which renders 

it unmodif table by the conat_funco function. * /

void conat_func(conat int* i) 

在上例中,同樣定義了乙個名為x的陣列,並對它的10個元素賦了初始值。函式const_func()的說明如下所示:

int const_func(const int·);

引數constint·告訴編譯程式const_func()函式只有乙個引數,即指向乙個int型別常量的指標。在呼叫const_func()函式時,同樣只需將陣列的位址傳遞給該函式,即:

const_rune(x);

在位址傳遞方式中,沒有複製初始陣列並將其拷貝存放在棧中,const_rune()函式只接收到指向乙個int型別常量的指標,因此在編寫程式時要保證傳遞給const_func()函式的是指向乙個由int型別值組成的陣列的指標。const修飾符的作用是防止const_func()函式意外地修改初始陣列中的某乙個元素。

位址傳遞方式唯一的不足之處是必須由程式本身來保證將乙個陣列傳遞給函式作為引數,例如,在函式const—rune()的原型和定義中,都沒有明確指示該函式的引數是指向乙個由int型別值組成的陣列的指標。然而,位址傳遞方式速度快,效率高,因此,在對執行速度要求比較高時,應該採用這種方式。

呼叫函式和被呼叫函式的關係

1 當在乙個函式的執行期間呼叫另乙個函式時,在執行被呼叫函式之前,系統需要完成三件事情 1 將所有的實參 返回位址等資訊傳遞給被呼叫函式儲存 2 為被呼叫函式的區域性變數分配儲存區 3 將控制轉移到被調函式的入口。2 從被呼叫函式返回到呼叫函式之前,系統要做三件事情 1 儲存被調函式的計算結果 2 ...

動態的呼叫可變引數函式

最近,碰到了乙個奇怪的問題 如何在函式中動態的呼叫可變引數函式。例如說,有某個可變引數函式 void func1 int a,現在給出乙個個數不定的動態陣列,把裡面的數值按順序的作為可變引數傳遞進 func1 函式中。當然,如果允許改變 func1 的定義,那麼我相信每個人都可以輕鬆的完成這個任務,...

c 函式呼叫引數傳遞

在c 中,引數傳遞的方式是 實虛結合 按值傳遞 pass by value 位址傳遞 pass by pointer 引用傳遞 pass by reference 按值傳遞的過程為 首先計算出實參表示式的值,接著給對應的形參變數分配乙個儲存空間,該空間的大小等於該形參型別的,然後把以求出的實參表示式...