C/C++ 基礎程式設計 我們必須讓小事也令人難忘 We ve got to make the small things unforgettable. -Steve Jobs 函式 (Function) 講師 : 張傑帆 CSIE NTU
課程大綱 函式概論 變數類型 - 全 / 區域變數 函式中以指標當參數 傳遞陣列參數 把程式拆成多個檔案
函式 (Function) 包函許多程式碼的一行程式 ( 用來代表某種功能 ) 當程式碼太多且會重覆出現時, 可以將部份程式碼抽離主程式, 寫成一段函式, 有需要用到時再去呼叫它 之前我們已經使用過 C 語言提供的函式, 現在我們要練習自己寫個函式來使用 內建函式 : main() /printf()/scanf() 也是函式, 這些都是系統提供的
函式的宣告 宣告一個函式並寫裡面的程式 要訣 : 取個函式名稱用來代表某個功能 函式名稱 這個功能需要給他什麼資料才能執行 參數 開始寫函式內的程式碼 程式碼 執行完後會回傳什麼資料給呼叫函式的程式 回傳值 函式內的變數是獨立的, 只有在函式內可以使用 回傳值資料型態 ( 不需回傳可用 void) 資料型態函式名稱 ( 資料型態參數 1, 資料型態參數 2,, 資料型態參數 n) 程式碼 ; return 回傳值 ; 傳入函式值資料型態 int func ( int var1, int var2) int var3 = var1+var2; return var3;
寫好的函式要放在哪裡呢? 由於使用者自定函式是無中生有的, 因此必須在使用前先定義該函式, 此即為該函式的主體 函式主體的位置通常撰寫在 #include 和 main() 主函式的之間, 即 main() 主函式的前面, 也允許放在 main() 主函式的後面, 若使用後者就必須在 main() 主函式前面先宣告函式的原型, 以告知編譯器此自定函式在程式中有定義 int func ( int var1, int var2) int var3 = var1+var2; return var3;
int func ( int, int ); int func ( int var1, int var2) int var3 = var1+var2; return var3; int func ( int var1, int var2) int var3 = var1+var2; return var3;
int func ( int, int ); int func ( int var1, int var2) int var3 = var1+var2; return var3;
8
函式的使用練習 宣告完的函式即可在其他函式或主程式 main 中呼叫並使用 下面 hello 為一個不需參數也不會回傳資料的函式 : #include <stdio.h> void hello(); // hello 函式的宣告 int main() printf(" 準備呼叫 hello()\n"); hello(); // 呼叫 hello 函式 printf(" 已呼叫過 hello()\n"); return 0; void hello() // hello 函式的程式碼 (void 代表不回傳資料 ) printf("hello\n"); printf("hello\n"); printf("hello\n");
(parameter) (argument)
函式的使用 : 參數與回傳值 要訣 : 資料傳遞需要先儲存! 參數 : 函式宣告儲存單元將傳入的值儲存 回傳值 : 函式將結果回傳給呼叫它的地方儲存 範例 : 使用函式計算數學公式 F(x, y) = 2x + y 90 F: 給定 x, y 兩值即可得 2x+y 之結果 90 90 #include <stdio.h> int F(int x, int y); int main() int num1, num2, ans; scanf("%d%d", &num1, &num2); ans = F(num1, num2); printf("f(%d, %d) = %d\n", num1, num2, ans); return 0; int F(int x, int y) int z = 2*x + y; return z;
函式的參數 - 傳值呼叫 (Call by value) 呼叫用的參數內容會被 copy 到函式用來接收參數的變數中, 也就是說, 呼叫時要傳入的參數, 和函式中接收用的參數, 事實上是兩個不同的變數 所以函式中改變參數數值時, 原來呼叫處的數值並不會改變 可以想像說, 函式中的參數會宣告成一個新的變數, 而它的初值會在呼叫時被設定成傳入的數值 執行程式後可以發現, 每個變數的記憶體位址都不一樣, 所以當然每個變數都是各自獨立的
函式的參數 : 易混淆的例子 範例 #include <stdio.h> void func(int i); int main() // 這裏的變數跟上面都沒有關係 int a=3; int b=2; int i=4; func(i); printf("%d %d %d\n",a,b,i); // 有沒有發現, 執行 func 的 i=5 後, 這裏的 i 仍然為 4 return 0; void func(int i) int a=2; int b=3; i=5; printf("%d %d %d\n",a,b,i);
在函式中結束程式 : exit(0); 在函式中如果要強制結束程式可以使用 exit 函式 #include <stdio.h> #include <stdlib.h> void func(); int main() func(); printf(" 這行不會印出 \n"); return 0; void func() printf(" 呼叫 exit 函式!\n"); exit(0);
練習 寫一個計算 1+2+3 +n 的函式 int sum(int n);
課程大綱 函式概論 變數類形 - 全 / 區域變數 函式中以指標當參數 傳遞陣列參數 把程式拆成多個檔案
全域變數與區域變數 C 語言將函式內所宣告的變數稱為區域變數 (Local Variable), 此類變數的有效範圍僅在該函式內, 離開該函式便由記憶體中釋放掉, 下次呼叫該函式時再重新配置記憶體給該函式使用 C 語言另外提供一種變數可供多個函式共同使用, 變數的有效時間一直到程式結束為止, 我們將此類的變數稱為 全域變數 (Global variable)
局部 / 區域變數 (Local Variable) 自動變數只在它所定義的區塊內有效 只要在變數所屬的區塊結構內執行, 該變數的資料是有效而正確的 當程式執行離開了該區塊, 所有於區塊內定義的 自動變數就不存在了 #include <stdio.h> void func(); int main() int x=1; func(); func(); printf("%d\n",x); return 0; x 2=>3 x x x x void func() int x=2; x = x + 1; printf("%d\n",x); 2=>3
區域變數的名稱可以重複使用 在不同函數內被宣告的區域變數就代表是 2 個不同的變數 21
全域變數 (Global Variable) 全域變數的有效範圍不是區域性, 而是整體性 變數定義在任何函數的外面, 表示可以被其他函數所共用 x #include <stdio.h> int x = 5; void func(); int main() func(); func(); printf("%d\n",x); return 0; x void func() x = x + 1; printf("%d\n",x); x
程式中區域變數與全域變數的名稱相同, 當存取函式內的變數時會以區域變數為優先, 使用時最好注意, 建議全域變數最好不要和區域變數的名稱重複, 以免參用時造成混淆 函數內的全域變數會被區域變數掩蓋掉
小練習 排列組合 24
課程大綱 函式概論 變數類別 函式中以指標當參數 傳遞陣列參數 把程式拆成多個檔案
傳址呼叫 call by address 所謂的 傳址呼叫 就是函式在做引數傳遞時, 呼叫函式中的實引數是將自己本身的記憶體位址傳給被呼叫函式內的引數 希望將回傳一個以上的結果時使用 傳址呼叫的設定方式是 : 定義的函式小括號內的虛引數必須宣告為指標變數 ( 即在變數前面加上 ) 呼叫函式內的引數必須傳送變數的記憶體位址 ( 即變數前面加上 &)
函式中以指標當參數 - 傳址呼叫 要是函式傳參數時, 傳的是變數的位址, 就可以在函式中去改變主程式中變數的內容了 範例 : swap, 兩變數資料交換 #include <stdio.h> void swap(int *, int *); int main() int num1 = 5; int num2 = 10; swap(&num1, &num2); printf("num1=%d\n", num1); printf("num2=%d\n", num2); return 0; void swap(int *px, int *py) int temp; 0x1000 0x1004 temp = *px; *px = *py; *py = temp;
傳值呼叫 call by value 若是想要定義交換引數 x 與 y 的 swap 函數, 就不能使用傳值的方式來傳遞引數, 因為傳值只是傳遞引數中的值而已, 並不會對引數本身產生改變, 所以只會交換參數
小練習 請試寫一函式可加總 1 到 n 和計算 n! 並利用指標同時將兩個結果送給原呼叫函式 void sum_fact( int n, int *sum, int *fact);
課程大綱 函式概論 變數類別 函式中以指標當參數 傳遞陣列參數 把程式拆成多個檔案
傳遞陣列參數 把陣列當參數來傳遞時, 要從記憶體的角度來看, 如果傳遞的只是陣列某欄位中的一個變數, 那和傳普通變數沒有什麼分別 Ex: int ary[5] = 1,2,3,4,5; func(ary[0]); 如果傳的是整個陣列, 傳遞的東西會是陣列的位址 Ex: int ary[5] = 1,2,3,4,5; func(ary);
傳遞陣列參數 範例 #include <stdio.h> #include <stdlib.h> void output(int n, int *p); int main() int a[5] = 1,2,3,4,5; int b[7] = 1,2,3,4,5,6,7; output(5, a); output(7, b); return 0; void output(int n, int *p) int i; for(i=0; i<n; i++) printf("%d ",p[i]); printf("\n"); void printary(int n, int *P);
傳遞陣列參數 : 平均值計算 寫一個回傳同學成績平均分數之函式 #include <stdio.h> #include <string.h> double average(int student, int *score); double average(int student, int *score) int i; double sum=0; double aver; for(i=0; i<student; i++) sum+=score[i]; aver = sum/student; return aver; int main() int student; int *score; double aver; int i; printf(" 請輸入學生人數 : "); scanf("%d", &student); score = (int *)malloc(sizeof(int) * student); for(i=0; i<student; i++) printf(" 學生 %d: ", i+1); scanf("%d", &score[i]); aver = average(student, score); printf(" 平均 : %.2lf 分 \n", aver); return 0;
練習 繼續上一範例, 寫一個回傳最高分成績位置之函式 void printary(int n, int *P); double Avg(int n, int *P); int MaxScore(int n, int *P);
傳遞陣列參數 : 字串處理 使用 upper 函式, 將字串中小寫英文轉大寫英文 #include <stdio.h> void upper(char *a); int main() char str[80]; gets(str); upper(str); printf("%s \n", str); return 0; void upper(char *a) int i=0; while(1) if(a[i]>='a' && a[i]<='z') a[i]-=32; else if(a[i] == '\0') break; i++;
課程大綱 函式概論 變數類別 函式中以指標當參數 傳遞陣列參數 把程式拆成多個檔案
把程式拆成多個檔案 要訣 : main.c 標頭檔.h 用來宣告函式名稱 ( 用來被 include) 程式檔.c 用來寫函式程式碼 ( 放到專案一起編譯與連結 ) #include <stdio.h> #include "hello.h" // hello() 的宣告在這裏面 int main() printf(" 準備呼叫 hello()\n"); hello(); // 呼叫 hello 函式 printf(" 已呼叫過 hello()\n"); return 0; #ifndef HELLO_H #define HELLO_H void hello(); // hello 函式的宣告 #endif #include "hello.h" #include <stdio.h> void hello() // hello 函式的程式碼 printf("hello\n"); printf("hello\n"); printf("hello\n"); hello.h hello.c
把程式拆成多個檔案 練習 : 將下述兩個函式分成 score.h 與 score.c, 並寫一個程式計算班上同學成績並列出平均與最高分 void printary(int n, int *P); double Avg(int n, int *P); int MaxScore(int n, int *P);
回家作業 - 質數判斷程式 請寫一函式令其可以判斷傳入參數是否為質數 int IsPrime(int num); 是質數的話回傳 1, 不是的話回傳 0 並將函式分成 prime.h prime.c 與 main.c
延申閱讀 static 靜態區域變數 函數指標 遞迴函式