函數的定義
函數定義的語法形式
數據類型 函數名(形式參數表){
函數體 //執行語句
}
注意
函數的數據類型是函數的返回值類型(若數據類型為 void ,則無返回值)。
函數名是標識符,一個程序中除了主函數名必須為main外,其余函數的名字按照標識符的取名規則可以任意選取,最好取有助於記憶的名字。
形式參數(簡稱形參)表可以是空的(即無參函數);也可以有多個形參,形參間用逗號隔開,不管有無參數,函數名后的圓括號都必須有。形參必須有類型說明,形參可以是變量名、數組名或指針名,它的作用是實現主調函數與被調函數之間的關系。
函數中最外層一對花括號“{ }”括起來的若干個說明語句和執行語句組成了一個函數的函數體。由函數體內的語句決定該函數功能。函數體實際上是一個復合語句,它可以沒有任何類型說明,而只有語句,也可以兩者都沒有,即空函數。
函數不允許嵌套定義。在一個函數內定義另一個函數是非法的。但是允許嵌套使用。
函數在沒有被調用的時候是靜止的,此時的形參只是一個符號,它標志着在形參出現的位置應該有一個什么類型的數據。函數在被調用時才執行,也就是在被調用時才由主調函數將實際參數(簡稱實參)值賦予形參。這與數學中的函數概念相似,如數學函數:f(x)= x^2+x+1
這樣的函數只有當自變量被賦值以后,才能計算出函數的值。
函數定義的例子
......
函數的形式
函數的形式從結構上說可以分為三種:無參函數、有參函數和空函數。它們的定義形式都相同。
無參函數
無參函數顧名思義即為沒有參數傳遞的函數,無參函數一般不需要帶回函數值,所以函數類型說明可以為void。
有參函數
有參函數即有參數傳遞的函數,一般需要帶回函數值。
空函數
空函數即函數體只有一對花括號,花括號內沒有任何語句的函數。例如,
函數名()
{ }
空函數不完成什么工作,只占據一個位置。在大型程序設計中,空函數用於擴充函數功能。
函數的聲明和調用
函數的聲明
調用函數之前先要聲明函數原型。在主調函數中,或所有函數定義之前,按如下形式聲明:
類型說明符 被調函數名(含類型說明的形參表);
如果是在所有函數定義之前聲明了函數原型,那么該函數原型在本程序文件中任何地方都有效,也就是說在本程序文件中任何地方都可以依照該原型調用相應的函數。如果是在某個主調函數內部聲明了被調用函數原型,那么該原型就只能在這個函數內部有效。
下面對js( )函數原型聲明是合法的。
int jc(int n);
int jc(int);
可以看到函數原型聲明與函數定義時的第一行類似,只多了一個分號,成為了一個聲明語句而已。
函數的調用
聲明了函數原型之后,便可以按如下形式調用函數:
函數名(實參列表)
實參列表中應給出與函數原型形參個數相同、類型相符的實參。在主調函數中的參數稱為實參,實參一般應具有確定的值。實參可以是常量、表達式,也可以是已有確定值的變量,數組或指針名。函數調用可以作為一條語句,這時函數可以沒有返回值。函數調用也可以出現在表達式中,這時就必須有一個明確的返回值。
函數的返回值
在組成函數體的各類語句中,值得注意的是返回語句 return。
它的一般形式是:
return(表達式);
其功能是把程序流程從被調函數轉向主調函數並把表達式的值帶回主調函數,實現函數的返回。所以,在圓括號表達式的值實際上就是該函數的返回值。其返回值的類型即為它所在函數的函數類型。當一個函數沒有返回值時,函數中可以沒有return語句,直接利用函數體的右花括號“}”,作為沒有返回值的函數的返回。
也可以有return語句,但return后沒有表達式。返回語句的另一種形式是:
return;
這時函數沒有返回值,而只把流程轉向主調函數。
函數的傳值傳址調用
函數傳值調用的特點是將調用函數的實參表中的實參值依次對應地傳遞給被調用函數的形參表中的形參。要求函數的實參與形參個數相等,並且類型相同。函數的調用過程實際上是對棧空間的操作過程,因為調用函數是使用棧空間來保存信息的。函數在返回時,如果有返回值,則將它保存在臨時變量中。然后恢復主調函數的運行狀態,釋放被調用函數的棧空間,按其返回地址返回到調用函數。
傳值調用
這種調用方式是將實參的數據值傳遞給形參,即將實參值拷貝一個副本存放在被調用函數的棧區中。在被調用函數中,形參值可以改變,但不影響主調函數的實參值。參數傳遞方向只是從實參到形參,簡稱單向值傳遞。舉個例子:
#include<iostream>
using namespace std;
void swap(int a,int b)
{ int tmp=a;a=b;b=tmp; }
int main()
{
int c=1,d=2;
swap(c,d);
cout<<c<<' '<<d<<endl;
return 0;
}
//程序輸出為:1 2
在此例中,雖然在swap函數中交換了a,b的值,但是在main中卻沒有交換。因為swap函數只是交換c,d兩變量副本的值,實參值沒有改變,並沒有達到交換的目的。
傳址調用
這種調用方式是將實參變量的地址值傳遞給形參,這時形參是指針,即讓形參的指針指向實參地址,這里不再是將實參拷貝一個副本給形參,而是讓形參直接指向實參,這就提供了一種可以改變實參變量的值的方法。現在用傳址調用來實現swap:
#include<iostream>
using namespace std;
void swap(int &a,int &b) //定義swap()函數,形參是傳址調用
{int tmp=a;a=b;b=tmp; }
int main()
{
int c=1,d=2;
swap(c,d); //交換變量
cout<<c<<' '<<d<<endl;
return 0;
}
//程序輸出為:2 1
在此例中,因為swap函數的參數為傳址調用,&a是指實參變量的地址值傳遞給形參,所以,在函數swap中修改a,b的值相當於在主函數main中修改c,d的值。
全局變量、局部變量及它們的作用域
在函數外部定義的變量稱為外部變量或全局變量,在函數內部定義的變量稱為內部變量或局部變量。
全局變量
全局變量的作用域是從變量定義的位置起直至本源文件結束止,即從定義位置之后的所有函數都可以訪問該全局變量。
注意
在一個函數內部,既可以使用本函數定義的局部變量,也可以使用在此函數前定義的全局變量。
全局變量的作用是使得函數間多了一種傳遞信息的方式。如果在一個程序中多個函數都要對同一個變量進行處理,即共享,就可以將這個變量定義成全局變量,使用非常方便,但副作用也不可低估。
過多地使用全局變量,會增加調試難度。因為多個函數都能改變全局變量的值,不易判斷某個時刻全局變量的值。
過多地使用全局變量,會降低程序的通用性。如果將一個函數移植到另一個程序中,需要將全局變量一起移植過去,同時還有可能出現重名問題。
全局變量在程序執行的全過程中一直占用內存單元。
全局變量在定義時若沒有賦初值,其默認值為0。
局部變量
局部變量的作用域是在定義該變量的函數內部。換句話說,局部變量只在定義它的函數內有效。在一個子程序內定義的變量也是局部變量,其作用域是該子程序。函數的形參也是局部變量。
由於局部變量的作用域僅局限於本函數內部,所以,在不同的函數中變量名可以相同,它們分別代表不同的對象,在內存中占據不同的內存單元,互不干擾。
一個局部變量和一個全局變量是可以重名的,在相同的作用域內局部變量有效時全局變量無效。即局部變量可以屏蔽全局變量。
這里需要強調的是,主函數main中定義的變量也是局部變量,這一點與其他程序設計語言不同。
全局變量數組初始全部為0,局部變量值是隨機的,要初始化初值,局部變量受棧空間大小限制,大數組需要注意。通俗說,局部變量的數組不能開很大,全局變量隨便。
並非原創,僅是整理,請見諒。