這一節(jié)我們介紹函數齐莲,我們這里的函數和數學上的函數的意思一樣么?答案是否定的篷牌。 有的編程語言比如Java就把函數成為方法臣咖,所以我們這里所要討論的 函數實際上就是一個解決一般問題的過程涩金,這個可以借助黑盒模型進行理解谱醇,現在函數就是一個黑盒,當我們向里面?zhèn)魅霐祿臅r候步做,黑盒處理之后給出我們結果副渴。
是不是很抽象?用鼠標只能畫成醬紫了(偷笑)全度。
對應于黑盒模型煮剧,我們的函數可以傳入0個或多個參數,然后返回一個結果将鸵,注意函數的出口只有一個那就是return語句勉盅,盡管在函數體中可能有多處出現return,但是我們要知道顶掉,函數最終返回到調用它的地方草娜,所以出口只有一個。
函數的標準寫法是什么呢痒筒?
我們有兩種方式表示函數
1.先聲明后實現
這里提一下main()函數宰闰,顧名思義,main()函數是程序的主函數簿透,也就是說移袍,我們的程序,從main()函數開始執(zhí)行老充,所以也稱為入口函數葡盗。
函數的標準寫法:
返回類型 函數名(參類型 [參數名],參類型 [參數名],...);//[表示可有可無]
int hello(int n);或者int hello(int);
我們可以在main函數中調用函數A啡浊,但是函數A必須在main函數之前聲明觅够,不然main函數就認為不存在函數A路狮,因為程序的編譯過程是從上而下的。
我們來看一段代碼(Let's look at the wrong code...)
#include<iostream>
#include<string>
using namespace std;
int hello(int n);
int main(){
hello(5);
return 0;
}
執(zhí)行的時候報錯蔚约,錯誤提示是說在main函數中引用了無法解析的符號奄妨,這是為什么呢?因為苹祟,盡管你盡管聲明了hello函數砸抛,告訴main函數有個叫hello的函數存在,但是树枫,這個函數真的存在么直焙?當main函數按照名字去尋找的時候,發(fā)現不認識這個函數砂轻,也就是說這個函數沒有定義奔誓。就像我們使用變量一樣,你聲明了一個變量搔涝,不給它賦值是不能直接拿來用的厨喂。
int n;
n = n+1;//這是不合法的,因為我們還沒有給變量n賦初值
為了能使main函數成功調用hello函數我們要給hello函數一個定義
比如我們這樣定義
int hello(int n){
for(int i =0;i<n;i++){
cout<<"hello world"<<endl;
}
return 0;
}
我們定義了hello函數庄呈,就是輸出n遍"hello world" 蜕煌,當然可以有不同的定義,這也就是黑盒模型的本質诬留,盒子里面可以是任何東西斜纪。
把這個定義加入到剛剛的例子中試一下
#include<iostream>
#include<string>
using namespace std;
int hello(int n);
int main(){
hello(5);
return 0;
}
int hello(int n){
for (int i = 0; i < n; i++){
cout << "hello world" << endl;
}
return 0;
}
great!
這樣我們的main函數就成功調用了hello函數文兑,并且輸入的數據是5盒刚,得到的結果是 屏幕上輸出5行"hello world" 是不是很簡單呀,快編寫你的第一個函數吧(當然不包括main函數啦绿贞,嘿嘿因块,因為每個程序都要有main函數)
2.同時聲明、實現
簡單的思考一下樟蠕,為了能夠讓main函數成功調用我們的函數A贮聂,我們要把函數的聲明放在main之前,所以實現部分也要在main之前寨辩。
返回類型 函數名稱(參數類型 參數名稱吓懈,參數類型 參數名稱...){
函數體
}
#include<iostream>
using namespace std;
int A(int n){
int result=1;
while (n)
result *= n--;
return result;
}
int main(){
cout << A(5) << endl;
return 0;
}
這里函數的聲明和實現放在了一起,但是必須要在調用它的函數之前靡狞。這個函數A的功能是計算n的階乘耻警。
以上實例都是main函數調用外部函數,那么函數之間能夠互相調用呢?答案是肯定的甘穿。
3.函數之間的調用
這里只要記住一條腮恩,就是無論調用哪個函數,所被調用函數必須在調用者函數之前聲明温兼。
int A(){
do something ...
}
int B(){
A();
}
這里的函數B就調用了函數A
有的人要問秸滴,那函數A能不能調用函數B呢,答案也是肯定的募判。但是在A之前要先聲明B看下面的例子
#include<iostream>
using namespace std;
void B();
void A(){
cout << "A" << endl;
B();
}
void B(){
cout << "B" << endl;
A();
}
int main(){
A();
return 0;
}
這里我們main函數調用了A荡含,A又調用了B,B又調用了A届垫,A又調用了B释液,...,沒錯装处,這將會一直調用下去误债,也就構成了死循環(huán)。
因為函數一直在調用妄迁,所以程序沒法終止寝蹈,截圖為部分。那么我們有必要兩個函數之間互相調用么判族,答案也是肯定的躺盛,因為我們外加一些條件就能夠很好的利用他們了,看下例
#include<iostream>
using namespace std;
static int n = 10;
void B();
void A(){
if (n < 0)
return;
n--;
cout << "A" << endl;
B();
}
void B(){
cout << "B" << endl;
A();
}
int main(){
A();
return 0;
}
既然相互調用會構成死循環(huán)形帮,我們就在函數里加入返回條件,若滿足條件則直接返回周叮,不在調用辩撑。這樣就能達到我們的目的了。
4.返回值類型
既然函數都要有返回類型仿耽,那么返回類型有哪些呢?
void
int
bool
char
string
float
...
沒錯只要能作為數據類型的都可以作為函數的返回類型合冀,
void表示返回為空,就是可以不返回项贺,或者直接return;
為什么要設置返回類型呢君躺? 因為函數的輸出結果大都會有類型,為了能夠在調用處正確的給變量賦值开缎,所以要寫明函數的返回值類型
5.形式參數(形參)
什么是形式參數呢棕叫?形參就是傳入到我們的黑盒(函數)的參數,在函數聲明和定義的時候使用的奕删,形參沒有具體的數值俺泣,只有數據類型,當我們調用這個函數的時候,我們用實參傳入伏钠,從而經過函數得到結果横漏,實參與形參對應,實參表示參數不僅有數據類型熟掂,而且有具體的數值缎浇。
#include<iostream>
using namespace std;
int A(int n){
return n*2;
}
int main(){
A(5);
return 0;
}
這個圖很好的反映了形參和實參的區(qū)別。
形參出現在函數定義中赴肚,在整個函數體都可用华畏,離開函數不能使用
實參出現在主調函數中,進入被調函數后也不能使用
函數調用時尊蚁,主調函數把實參的值傳遞給被調函數的形參亡笑,從而完成從主調函數向被調函數的數據傳送。
函數的基本問題就講到這里横朋,以后會經常用到各種函數仑乌。