這篇文章主要介紹了詳解C++編程中對于函數的使用,包括函數的參數和返回值以及調用等基本的知識點,需要的朋友可以參考下
形式參數和實際參數
在調用函數時,大多數情況下,函數是帶參數的。主調函數和被調用函數之間有數據傳遞關系。前面已提到:在定義函數時函數名后面括號中的變量名稱為形式參數(formal parameter,簡稱形參),在主調函數中調用一個函數時,函數名后面括號中的參數(可以是一個表達式)稱為實際參數(actual parameter,簡稱實參)。
【例】調用函數時的數據傳遞。
- #include <iostream>
- using namespace std;
- int max(int x,int y) //定義有參函數max
- {
- int z;
- z=x>y?x:y;
- return(z);
- }
- int main( )
- {
- int a,b,c;
- cout<<"please enter two integer numbers:";
- cin>>a>>b;
- c=max(a,b);//調用max函數,給定實參為a,b。函數值賦給c
- cout<<"max="<<c<<endl;
- return 0;
- }
運行情況如下:
- please enter two integer numbers:2 3↙
- max=3
有關形參與實參的說明:
1) 在定義函數時指定的形參,在未出現函數調用時,它們并不占內存中的存儲單元,因此稱它們是形式參數或虛擬參數,表示它們并不是實際存在的數據,只有在發生函數調用時,函數max中的形參才被分配內存單元,以便接收從實參傳來的數據。在調用結束后,形參所占的內存單元也被釋放。
2) 實參可以是常量、變量或表達式,如max(3, a+b);但要求a和b有確定的值。以便在調用函數時將實參的值賦給形參。
3) 在定義函數時,必須在函數首部指定形參的類型(見示例程序第3行)。
4) 實參與形參的類型應相同或賦值兼容。例4.2中實參和形參都是整型,這是合法的、正確的。如果實參為整型而形參為實型,或者相反,則按不同類型數值的賦值規則進行轉換。例如實參a的值為3.5,而形參x為整型,則將3.5轉換成整數3,然后送到形參b。字符型與整型可以互相通用。
5) 實參變量對形參變量的數據傳遞是“值傳遞”,即單向傳遞,只由實參傳給形參,而不能由形參傳回來給實參。在調用函數時,編譯系統臨時給形參分配存儲單元。
請注意:實參單元與形參單元是不同的單元。下圖表示將實參a和b的值2和3傳遞給對應的形參x和y。
調用結束后,形參單元被釋放,實參單元仍保留并維持原值。因此,在執行一個被調用函數時,形參的值如果發生改變,并不會改變主調函數中實參的值。例如,若在執行max函數過程中形參x和y的值變為10和15,調用結束后,實參a和b仍為2和3,見上圖。
函數的返回值
1) 函數的返回值是通過函數中的return語句獲得的。return語句將被調用函數中的一個確定值帶回主調函數中去。
return語句后面的括號可以要,也可以不要。return后面的值可以是一個表達式。
2) 函數值的類型。既然函數有返回值,這個值當然應屬于某一個確定的類型,應當在定義函數時指定函數值的類型。
3) 如果函數值的類型和return語句中表達式的值不一致,則以函數類型為準,即函數類型決定返回值的類型。對數值型數據,可以自動進行類型轉換。
函數調用的一般形式
函數調用的一般形式為:
- 函數名([實參表列]);
如果是調用無參函數,則“實參表列”可以沒有,但括號不能省略。如果實參表列包含多個實參,則各參數間用逗號隔開。實參與形參的個數應相等,類型應匹配(相同或賦值兼容)。實參與形參按順序對應,一對一地傳遞數據。但應說明,如果實參表列包括多個實參,對實參求值的順序并不是確定的。
函數調用的方式
按函數在語句中的作用來分,可以有以下3種函數調用方式:
(1)函數語句
把函數調用單獨作為一個語句,并不要求函數帶回一個值,只是要求函數完成一定的操作。如例4.1中的printstar( );
(2)函數表達式
函數出現在一個表達式中,這時要求函數帶回一個確定的值以參加表達式的運算。如c=2*max(a, b);
(3)函數參數
函數調用作為一個函數的實參。如:
- m=max(a, max(b, c)); //max(b, c)是函數調用,其值作為外層max函數調用的一個實參
對被調用函數的聲明和函數原型
在一個函數中調用另一個函數(即被調用函數)需要具備以下條件:
首先被調用的函數必須是已經存在的函數。
如果使用庫函數,一般還應該在本文件開頭用#include命令將有關頭文件“包含”到本文件中來。
如果使用用戶自己定義的函數,而該函數與調用它的函數(即主調函數)在同一個程序單位中,且位置在主調函數之后,則必須在調用此函數之前對被調用的函數作聲明。
所謂函數聲明(declare),就是在函數尚在未定義的情況下,事先將該函數的有關信息通知編譯系統,以便使編譯能正常進行。
【例】對被調用的函數作聲明。
- #include <iostream>
- using namespace std;
- int main( )
- {
- float add(float x,float y); //對add函數作聲明
- float a,b,c;
- cout<<"please enter a,b:";
- cin>>a>>b;
- c=add(a,b);
- cout<<"sum="<<c<<endl;
- return 0;
- }
- float add(float x,float y)//定義add函數
- {
- float z;
- z=x+y;
- return (z);
- }
運行情況如下:
- please enter a, b: 123.68 456.45↙
- sum=580.13
注意:對函數的定義和聲明不是同一件事情。定義是指對函數功能的確立,包括指定函數名、函數類型、形參及其類型、函數體等,它是一個完整的、獨立的函數單位。而聲明的作用則是把函數的名字、函數類型以及形參的個數、類型和順序(注意,不包括函數體)通知編譯系統,以便在對包含函數調用的語句進行編譯時,據此對其進行對照檢查(例如函數名是否正確,實參與形參的類型和個數是否一致)。
其實,在函數聲明中也可以不寫形參名,而只寫形參的類型,如
- float add(float, float);
這種函數聲明稱為函數原型(function prototype)。使用函數原型是C和C++的一個重要特點。它的作用主要是: 根據函數原型在程序編譯階段對調用函數的合法性進行全面檢查。如果發現與函數原型不匹配的函數調用就報告編譯出錯。它屬于語法錯誤。用戶根據屏幕顯示的出錯信息很容易發現和糾正錯誤。
函數原型的一般形式為:
- 函數類型 函數名(參數類型1, 參數類型2…);
或
- 函數類型 函數名(參數類型1 參數名1, 參數類型2 參數名2…);
第(1)種形式是基本的形式。為了便于閱讀程序,也允許在函數原型中加上參數名,就成了第(2)種形式。但編譯系統并不檢查參數名。因此參數名是什么都無所謂。上面程序中的聲明也可以寫成
- float add(float a, float b); //參數名不用x、y,而用a、b
效果完全相同。
應當保證函數原型與函數首部寫法上的一致,即函數類型、函數名、參數個數、參數類型和參數順序必須相同。在函數調用時函數名、實參類型和實參個數應與函數原型一致。
兩點說明:
1) 前面已說明,如果被調用函數的定義出現在主調函數之前,可以不必加以聲明。因為編譯系統已經事先知道了已定義的函數類型,會根據函數首部提供的信息對函數的調用作正確性檢查。
有經驗的程序編制人員一般都把main函數寫在最前面,這樣對整個程序的結構和作用一目了然,統覽全局,然后再具體了解各函數的細節。此外,用函數原型來聲明函數,還能減少編寫程序時可能出現的錯誤。由于函數聲明的位置與函數調用語句的位置比較近,因此在寫程序時便于就近參照函數原型來書寫函數調用,不易出錯。所以應養成對所有用到的函數作聲明的習慣。這是保證程序正確性和可讀性的重要環節。
2) 函數聲明的位置可以在調用函數所在的函數中,也可以在函數之外。如果函數聲明放在函數的外部,在所有函數定義之前,則在各個主調函數中不必對所調用的函數再作聲明。例如:
- char letter(char, char); //本行和以下兩行函數聲明在所有函數之前且在函數外部
- float f(float, float); //因而作用域是整個文件
- int i(float, float);
- int main( )
- {…}//在main函數中不必對它所調用的函數作聲明
- char letter(char c1, char c2) //定義letter函數
- {…}
- float f(float x, float y)//定義f函數
- {…}
- int i(float j, float k) //定義i函數
- {…}
如果一個函數被多個函數所調用,用這種方法比較好,不必在每個主調函數中重復聲明。
新聞熱點
疑難解答