函數 8-1 函數 函數 (function) 可以整合某些特定的處理 整合好的處理可以隨時呼叫使用 C 語言的程式本身也是一個函數, 也就是 main() 函數 使用函數可簡化程式 提款的處理 1. 將提款卡插入自動提款機當中 2. 輸入個人密碼 3. 指定提款金額 4. 領取款項 5. 確認款項與提款卡 提款處理
8-2 函數的定義與呼叫 定義函數的語法 : 傳回值的型態函數名稱 ( 引數列表 ) { 敘述 ; return 運算式 ; } 範例 :
呼叫函數的語法 : 函數名稱 ( 引數列表 ); 範例 :
使用函數的處理流程為 : 1. 呼叫函數 ;2. 執行函數中的處理 ;3. 回到呼叫處 也可以多次呼叫函數, 範例如下 :
8-3 引數 使用引數傳遞資料 當要呼叫出函數時, 可以進行以下的處理 : 從呼叫處將某項資料 ( 值 ) 傳遞到函數內 依照這項值來執行相對應之處理 要傳遞給函數的資料稱為引數 (argument)
傳遞引數給函數的範例如下 : #include <stdio.h> /* buy 函數的定義 */ void buy(int x) { printf(" 買了 %d 萬元的車子 \n", x); } /* buy 函數的呼叫 */ int main(void) { buy(20); buy(50); 買了 20 萬元的車子 買了 50 萬元的車子 } return 0; 在這個 main() 函數當中, 會執行以下處理 : 第一次呼叫出 buy() 函數時, 傳遞 20 這個值之後再呼叫第二次呼叫出 buy() 函數時, 傳遞 50 這個值之後再呼叫
函數本身所定義的引數 ( 變數 ) 稱為參數 (parameter) 另一方面, 從函數的呼叫來源所傳遞的引數 ( 值 ) 則稱為引數 (argument) 所以之前例子的變數 x 是參數, 20 和 50 則是引數
將從鍵盤輸入的值傳到函數中 : #include <stdio.h> /* buy 函數的定義 */ void buy(int x) { printf(" 買了 %d 萬元的車子 \n", x); } /* buy 函數的呼叫 */ int main(void) { int num; printf(" 第 1 台要買多少錢的車子? \n"); scanf("%d", &num); buy(num); 在 C 語言中, 傳遞到函數的並不是引數本身, 而是儲存在其中的 值 這種引數的傳遞方法稱為傳值 (pass by value) } printf(" 第 2 台要買多少錢的車子? \n"); scanf("%d", &num); buy(num); return 0; 這裡使用 main() 函數當中所準備的變數 num ( 的值 ), 作為由呼叫來源傳遞到函數的引數 所以會將由鍵盤讀取到 num 的值傳遞到函數中
函數可以帶有多個引數, 但在呼叫時要用逗號 (,) 來區隔所指定的多個引數, 這些引數又叫做 引數列表, 它們會依指定的順序傳遞給參數 範例 :
定義沒有引數的函數時, 可以省略引數型態的指定, 或指定為 void 型態 範例 :
8-4 傳回值 理解傳回值的機制 從函數本身傳回特定資訊到函數的呼叫來源處 從函數所傳回的資訊稱為傳回值 (return value) 它與可以多重指派的引數不同, 傳回值只能有一個 定義函數的語法 : 傳回值的型態函數名稱 ( 引數列表 ) { 敘述 ;... } return 運算式 ;
可以在呼叫來源處使用傳回值來進行處理 範例 :
沒有傳回值的函數 範例 : /* buy 函數的定義 */ void buy(void) { printf(" 買了車子 \n"); } 在不帶傳回值的函數中, 要先將傳回值的型態設定為 void 也可利用以下這個單純的 return 敘述來結束函數 : /* buy 函數的定義 */ void buy(void) { printf(" 買了車子 \n"); return; }
8-5 函數的利用 求合計值的函數 : #include <stdio.h> /* sum 函數的定義 */ int sum(int x, int y) { return x+y; } 接收兩個數值 進行傳回合計值的處理 int main(void) { int num1, num2, ans; printf(" 請輸入第 1 個整數 :\n"); scanf("%d", &num1); printf(" 請輸入第 2 個整數 :\n"); scanf("%d", &num2); ans = sum(num1, num2); printf(" 合計為 %d \n", ans); return 0; } 呼叫函數 輸出傳回值
求最大值的函數 : #include <stdio.h> /* max 函數的定義 */ int max(int x, int y) { if (x > y) return x; else return y; } int main(void) { int num1, num2, ans; printf(" 請輸入第 1 個整數 :\n"); scanf("%d", &num1); printf(" 請輸入第 2 個整數 :\n"); scanf("%d", &num2); ans = max(num1, num2); printf(" 最大值為 %d \n",ans); return 0; } 接收兩個數值當 x 大於 y 的時候 傳回 x 的值如果不是的時候, 則傳回 y 的值呼叫函數輸出傳回值 C 語言可以進行自己呼叫自己的處理, 這種機制就叫做遞迴
理解函數形式巨集的機制 函數形式巨集的定義 : #define 巨集名稱 ( 引數 ) ( 運算式 ) 範例 : #define MAX(x, y) (x, y? x : y) 函數形式巨集的呼叫 : 巨集名稱 ( 引數 ); 範例 : ans = MAX(num1, num2); ans = (num1 > num2? Num1 : num2); 定義函數形式巨集可以用來代替函數
使用函數形式巨集之範例 : #include <stdio.h> #define MAX(x, y) (x > y? x : y) 在這裡定義函數形式巨集 int main(void) { int num1, num2, ans; printf(" 請輸入第 1 個整數 \n"); scanf("%d", &num1); printf(" 請輸入第 2 個整數 \n"); scanf("%d", &num2); ans = MAX(num1, num2); printf(" 最大值為 %d \n", ans); return 0; } 這部份的程式碼會藉由前置處理器來進行置換 使用函數形式巨集的注意事項 : 呼叫函數形式巨集的引數可以是任何型態 若是要建立較不容易出錯的程式, 還是應該使用函數
8-6 變數與生存空間 理解變數的種類 在函數當中宣告的變數稱為區域變數 (local variable), 而在函數外部宣告的變數則稱為全域變數 (global variable)
理解生存空間 (scope) 生存空間 (scope) 是指變數在程式中的有效範圍, 也就是它的生存空間, 看它是區域或是全域的變數 宣告位置 生存空間 區域變數 函數內部 從宣告變數的地方開始到函數結束為止都可利用 全域變數 函數外部 任何函數都可以利用
理解變數的生存空間之範例 : #include <stdio.h> int a = 0; /* func 函數的定義 */ void func(void) { int c = 2; printf(" 在 func 函數當中可以使用變數 a 和變數 c \n"); printf(" 變數 a 的值為 %d \n", a); /* printf(" 變數 b 的值為 %d \n", b); */ printf(" 變數 c 的值為 %d \n", c); } /* main 函數的定義 */ int main(void) { int b = 1; 全域變數 a 區域變數 c 區域變數 b printf(" 在 main 函數當中可以使用變數 a 和變數 b \n"); printf(" 變數 a 的值為 %d \n", a); printf(" 變數 b 的值為 %d \n", b); /* printf(" 變數 c 的值為 %d \n", c); */ func(); return 0; } 可以使用全域變數 無法使用其他函數內的區域變數 可以使用這個函數中的區域變數 可以使用全域變數 無法使用其他函數內的區域變數
區域變數的名稱可以重複使用 位在不同函數內的區域變數, 即使名稱相同, 也不是同一個變數 在不同函數內被宣告的區域變數, 就代表是 2 個不同的變數
全域變數的名稱可以重複使用 全域變數與區域變數可以使用相同的名稱, 此時該函數內的全域變數會被區域變數掩蓋掉
8-7 變數的生命週期 變數或是陣列從程式開始到結束為止, 並不是一直保持儲存著值的狀態 我們可以把這段狀態視為是變數的 一生 從變數的儲存空間建立, 到儲存數值的這段期間, 就稱為變數的生命週期
區域變數的生命週期 : 當變數在函數內部被宣告時, 就會在記憶體內配置其所需的空間 當函數結束時, 就丟棄所配置的空間, 使記憶體可以用在其他方面 區域變數的生命週期
全域變數的生命週期 : 在程式本身的處理開始之前, 先暫時配置記憶體 程式結束的時候釋放記憶體 全域變數的生命週期
如果指定為 static 的話? 指定了 static 關鍵字的區域變數, 就會擁有和全域變數一樣長的生命週期, 這種區域變數就叫做靜態區域變數 static 又叫做記憶類別指定字 (storage class identifier) 記憶類別 生存空間 區域變數 ( 自動 ) 起於宣告, 終於函數結束 ( 自動 ) static 起於程式準備執行時, 終於程式結束 ( 靜態 ) 全域變數起於程式準備執行時, 終於程式結束 ( 靜態 ) 變數的生命週期
8-8 函數的宣告 函數原型宣告 語法 : 傳回值的型態函數名稱 ( 引數列表 ); 在 C 語言可以先告知編譯器 函數的名稱及引數的數目 這項功能就稱為函數原型宣告 ( 函數宣告 :function declaration) 函數原型宣告是在呼叫函數之前, 先寫下所呼叫函數的名稱 傳回值的型態 引數
製作大型程式時會用到許多函數, 這些函數不是記敘在與 main() 函數相同的檔案內, 而是分割到其他的檔案 分割檔案的範例如下 : myfunc.h /* max 函數的宣告 */ int max(int x, int y); myfunc.c /* max 函數的定義 */ int max(int x, int y) { if (x > y) return x; else return y; }
Sample13.c #include <stdio.h> #include "myfunc.h" 讀入標頭檔 int main(void) { int num1, num2, ans; printf(" 請輸入第 1 個整數 \n"); scanf("%d",&num1); printf(" 請輸入第 2 個整數 \n"); scanf("%d",&num2); ans = max(num1, num2); printf(" 最大值為 %d \n", ans); return 0; } 呼叫其他檔案的函數 myfunc.h 函數原型宣告 myfunc.c 已做好的 max() 函數的定義 Sample13.c main() 函數的定義 ( 程式主體 )
分別編譯 Sample13.c 和 myfunc.c, 將它們做成不同的目的檔, 再以連結的方式把這些目的檔串連成一個程式 myfunc.h 是只負責記述函數原型宣告的標頭檔 檔案的分割
理解標準程式庫函數的機制 C 語言的開發環境預先定義好的函數, 就叫做標準函數庫 (standard library) 使用標準函數庫的標頭檔, 要加上 < >, 而使用自己製作的標頭檔, 則要加上