函數 (function) 是一種功能性的模組,可以將程式 (program) 分割成小部分,藉由呼叫函數安排執行順序
定義函數需要指定函數的回傳值型態 (return type) 、函數名稱與小括弧中的參數列 (parameter list) ,後面的大括弧區域為函數工作的程式碼區域,如果有定義回傳值型態,大括弧中至少要有一個 return 陳述 (statement) 。我們舉一例如下
001 | int big(int a, int b) { |
002 | // 判斷兩個參數的大小 |
003 | if (a > b) { |
004 | // a 大於 b ,回傳 a |
005 | return a; |
006 | } |
007 | else { |
008 | // a 小於 b ,回傳 b |
009 | return b; |
010 | } |
011 | } |
big() 函數回傳兩個參數 (parameter) 中的較大值,我們可以看到回傳值型態為 int ,函數名稱為 big ,參數數量則是依需求自己定義,這裡為兩個 a 與 b ,型態都是 int 。
這裡, a 與 b 都是屬於 big() 內的區域變數 (local variable) ,也就是效力僅限於 big() 後的大括弧中。
也可以不定義參數,這時參數列可宣告為 void 或留空白。
此例用了兩個 return ,有回傳值的函數至少要有一個 return , return 就是函數結束執行,將控制權交還原本呼叫函數的地方, return 後只能接運算式 (expression) 或單一數值。我們將 big() 寫成一個完整範例
001 | #include <iostream> |
002 | |
003 | using namespace std; |
004 | |
005 | // 宣告 big() 的函數原型 |
006 | int big(int, int); |
007 | |
008 | // main() 由作業系統呼叫,回傳整數給作業系統 |
009 | int main(void) { |
010 | cout << endl; |
011 | // 呼叫 big() 並且印出回傳值 |
012 | cout << big(22, 11) << " is bigger!"; |
013 | cout << endl << endl; |
014 | |
015 | return 0; |
016 | } |
017 | |
018 | // 函數 big() 的實際定義 |
019 | int big(int a, int b) { |
020 | // 判斷兩個參數的大小 |
021 | if (a > b) { |
022 | // a 大於 b ,回傳 a |
023 | return a; |
024 | } |
025 | else { |
026 | // a 小於 b ,回傳 b |
027 | return b; |
028 | } |
029 | } |
030 | |
031 | /* 檔名: big_demo.cpp |
032 | 作者: Kaiching Chang |
033 | 時間: 2014-5 */ |
此例在函數定義前先加入函數原型 (function prototype) 的宣告 (declaration) ,宣告亦為一行陳述,因此結尾要加分號
005 | // 宣告 big() 的函數原型 |
006 | int big(int, int); |
宣告函數原型不需要加入參數的識別字,另外函數也可以不經宣告函數原型直接定義,此時函數定義就得放在 main() 之前。
我們在 main() 中呼叫 big() ,當 big() 執行完會在回到原本呼叫的地方,由於 big() 回傳一個整數,因此這裡就會直接印出 big() 的回傳值
011 | // 呼叫 big() 並且印出回傳值 |
012 | cout << big(22, 11) << " is bigger!" << endl; |
編譯後執行,結果如下
上例只有在 main() 中呼叫 big() 一次,如果有很多個數字需要比較,自然可以需要的次數呼叫。
函數的一個特點就是重複執行的程式碼用自行定義的識別字 (identifier) 代替,另舉一例如下
001 | #include <iostream> |
002 | |
003 | using namespace std; |
004 | |
005 | // 宣告函數原型 |
006 | void PrintInt(int); |
007 | void PrintNewline(void); |
008 | |
009 | int main(void) { |
010 | int i = 10; // 設定倒數的初值 |
011 | |
012 | PrintNewline(); // 印出空白一行 |
013 | while (i > 0) { |
014 | PrintInt(i); // 印出數字 |
015 | i--; // 倒數 |
016 | } |
017 | PrintNewline(); // 印出空白一行 |
018 | |
019 | return 0; |
020 | } |
021 | |
022 | // 印出參數 |
023 | void PrintInt(int a) { |
024 | cout << a << endl; |
025 | } |
026 | |
027 | // 印出新行 |
028 | void PrintNewline(void) { |
029 | cout << endl; |
030 | } |
031 | |
032 | /* 檔名: print_demo.cpp |
033 | 作者: Kaiching Chang |
034 | 時間: 2014-5 */ |
這是我們之前寫過的倒數計時程式,只是將印出的工作定義給函數,這裡可以看到函數名稱可以使程式有清楚的語意
012 | PrintNewline(); // 印出空白一行 |
013 | while (i > 0) { |
014 | PrintInt(i); // 印出數字 |
015 | i--; // 倒數 |
016 | } |
017 | PrintNewline(); // 印出空白一行 |
編譯執行的結果是一樣的
函數是最基本也是最簡單的功能模組,可是 C++ 是物件導向程式語言 (object-oriented programming language) ,物件中除了可以有函數也可以有變數,接下來,我們來看看怎麼樣來設計物件吧!
中英文術語對照
函數 | function |
程式 | program |
回傳值型態 | return type |
參數列 | parameter list |
陳述 | statement |
參數 | parameter |
區域變數 | local variable |
運算式 | expression |
函數原型 | function prototype |
宣告 | declaration |
識別字 | identifier |
物件導向程式語言 | object-oriented programming language |
重點整理
- 函數為程式中功能性的模組,程式可藉由呼叫函數排列執行順序。
- 定義函數須包括回傳值型態、函數名稱、參數列及函數的程式區塊。
- 若不宣告函數原型,就得把函數定義放在 main() 之前。
- 函數可以有回傳值,也可以沒有回傳值,有回傳值的函數利用 return 回傳數值。
- 函數可以有參數,也可以沒有參數,沒有參數的函數在參數列宣告 void 或留空白。
- 函數名稱為自行定義的識別字,可以有比較清楚的語意。
- C++ 為物件導向程式語言,物件中除了有物件自己的函數,也可以有物件自己的變數。
問題與討論
- 參數跟回傳值在函數中的用途為何?為什麼可以有多個參數,卻只能有一個回傳值?
- 在函數中可以改變參數的值嗎?
- 什麼是區域變數?為什麼說參數是區域變數?
練習
- 寫一個程式 exercise0901.cpp ,裡頭設計一個函數 sum() ,用以計算兩個整數的和。
- 承上題,另寫一個程式 exercise0902.cpp ,改成接受使用者輸入的版本。
- 寫一個程式 exercise0903.cpp ,裡頭設計一個函數 sum() ,只用一個整數參數 p ,結果回傳 1 到 p 之間所有正整數的和。
- 承上題,另寫一個程式 exercise0904.cpp ,改成接受使用者輸入的版本。
- 寫一個程式 exercise0905.cpp ,裡頭設計一個函數 factorial() ,用以計算階層值。
- 承上題,另寫一個程式 exercise0906.cpp ,改成用遞迴方式設計 factorial() 。
- 承上題,另寫一個程式 exercise0907.cpp ,改成接受使用者輸入的版本。
- 寫一個程式 exercise0908.cpp ,裡頭設計一個函數 fibonacci() ,用以計算費氏數列。
- 承上題,另寫一個程式 exercise0909.cpp ,改成用遞迴方式設計 fibonacci() 。
- 承上題,另寫一個程式 exercise0910.cpp ,改成接受使用者輸入的版本。
the end
沒有留言:
張貼留言