Function
輸出: #include <stdio.h> #include <string.h> #define NAME "NTHU CS" #define ADDRESS "101, Sec. 2, Kuang Fu Rd." #define PLACE "Hsinchu, 300 Taiwan" #define WIDTH 40 #define SPACE ' ' void show_n_char(char ch, int num); int main(void) { int spaces; show_n_char('*', WIDTH); putchar('\n'); show_n_char(SPACE, 17); printf("%s\n", NAME); spaces = (WIDTH - strlen(ADDRESS)) /2; show_n_char(SPACE, spaces); printf("%s\n", ADDRESS); show_n_char(SPACE, (WIDTH - strlen(PLACE)) / 2); printf("%s\n", PLACE); return 0; } void show_n_char(char ch, int num) int count; for (count = 1; count <= num; count++) putchar(ch); 輸出: **************************************** NTHU CS 101, Sec. 2, Kuang Fu Rd. Hsinchu, 300 Taiwan 範例3-1
它做的事情很簡單,只要一個 for 迴圈就可以辦到 void show_n_char(char ch, int num); int main(void) {...} void show_n_char(char ch, int num) { int count; for (count = 1; count <= num; count++) putchar(ch); } 我們用自訂的 show_n_char()來輸出一長條以相同字元組成 的字串,我們希望 show_n_char()要傳入兩個參數,分別用來指 定輸出的字元以及長度 它做的事情很簡單,只要一個 for 迴圈就可以辦到 宣告 (prototype) 的地方要寫 void show_n_char(char ch, int num); 表示第一個參數的型別是 char,第二個參數的型別是 int。傳 回值的型別則還是寫 void,表示不需要回傳任何值
其實在宣告的時候,變數名稱並不重要,重要的是型別要寫對 void show_n_char(char ch, int num); int main(void) {...} void show_n_char(char ch, int num) { int count; for (count = 1; count <= num; count++) putchar(ch); } 其實在宣告的時候,變數名稱並不重要,重要的是型別要寫對 所以 function 宣告也可以寫成 void show_n_char(char , int ); 因為宣告的時候,還不需要真正產生變數。要等到定義的時候, 才需要產生變數,那時候就一定要寫變數名稱。
show_n_char('*', WIDTH); show_n_char(SPACE, 17); spaces = (WIDTH - strlen(ADDRESS)) /2; show_n_char(SPACE, spaces); show_n_char(SPACE, (WIDTH - strlen(PLACE)) / 2); 使用 show_n_char()只要把我們想要顯示的字元和數量當參數傳進 去,show_n_char()就可以依照它們來顯示 這些不同的寫法,最後做的動作其實都一樣,因為最後其實傳的是 int 值。 像 show_n_char(SPACE, (WIDTH - strlen(PLACE)) / 2); 其實會先把 (WIDTH - strlen(PLACE)) / 2 算出來 得到10,然後把10這個值當參數傳 給show_n_char() show_n_char()並不需要知道外面究竟做了什麼事,只要知道傳進來的第 二個參數的值是 10就夠了。若以 show_n_char(SPACE, spaces); 這個 例子來說,傳進去的也是當時變數 spaces 的值 (值為 7 )。
function 主體 (definition) 的部份則在右上角,用了迴圈來計算次方。 double power(double n, int p) { double pow = 1; int i; for (i = 1; i <= p; i++) { pow *= n; } return pow; } #include <stdio.h> double power(double n, int p); int main(void) { double x, xpow; int exp; printf("Enter a number and the positive integer power\n"); printf(" to which the number will be raised. Enter q to quit.\n"); while (scanf("%lf%d", &x, &exp) == 2) { xpow = power(x, exp); printf("%.3f to the power %d is %.5f\n", x, exp, xpow); printf("Enter next pair of numbers or q to quit.\n"); } printf("\nBye!\n"); return 0; } 宣告 範例3-2 自定的 function取名為 power(),用來計算某個數的整數次方,由宣告可 以看出 power() 要傳入兩個參數,分別是型別為 double 的底數 n 以及型 別為 int 的指數 p。 function 主體 (definition) 的部份則在右上角,用了迴圈來計算次方。 這樣的模組化程式設計方式是我們學習 C 語言要多加練習的重點之一。
黑盒子 把 function 想成一個黑盒子,使用 function 的時候可以不管 它裡面到底怎麼做的,只要確定它可以辦 到我們想要做的事情, 然後知道要傳什麼樣的參數就夠了 由於這種黑盒子的特性,我們不必擔心定義在 function 裡面的 變數是否會和外部的變數衝突 假設 main() 裡面有個變數叫做 x,然後某個 function f() 裡也 有個變數 x, 則更改f() 裡的x並不會改變main()裡的x。 再重複強調一次,當參數傳入 function 時,只有值會被複製傳 入,所以在 function 裡對參數做修改,同樣也是不會影響外部 的變數值
#include <stdio.h> void f(int x); int main(void) { int x = 1; printf("main: %d\n", x); f(x); return 0; } void f(int x) x++; printf("f: %d\n", x); 輸出: main: 1 f: 2 範例3-3 一開始在main()裡面x的值被設為 1 然後把x當參數傳入f(),在 functionf()裡 的 local variable 也叫做 x ,這個 x 因為接收傳入的參數,所以 值也是 1 在 f() 裡做了 x++; 所以 x 的值變成 2,然後 f() 結束回到 main(), 這時 main() 裡的 x 和呼叫 f() 前沒有兩樣,所以值還是 1
Function 程式執行行為
Memory #include <stdio.h> void fun_1(void); void fun_2(int); int main(void) { fun_1(); printf("goodbye goodbye\n"); return 0; } void fun_1(void) int imidate=1; fun_2(imidate); printf("goodbye fun_1\n"); void fun_2(int a) int b = a; Memory
Frame for main() Memory #include <stdio.h> void fun_1(void); void fun_2(int); int main() { fun_1(); printf("goodbye goodbye\n"); return 0; } void fun_1(void) int imidate=1; fun_2(imidate); printf("goodbye fun_1\n"); void fun_2(int a) int b = a; Frame for main() Memory
Frame for main() Frame for fun_1() Memory #include <stdio.h> void fun_1(void); void fun_2(int); int main() { fun_1(); printf("goodbye goodbye\n"); return 0; } void fun_1(void) int imidate=1; fun_2(imidate); printf("goodbye fun_1\n"); void fun_2(int a) int b = a; Frame for main() Frame for fun_1() Memory
Frame for main() Frame for fun_1() Frame for fun_2() Memory #include <stdio.h> void fun_1(void); void fun_2(int); int main() { fun_1(); printf("goodbye goodbye\n"); return 0; } void fun_1(void) int imidate=1; fun_2(imidate); printf("goodbye fun_1\n"); void fun_2(int a) int b = a; Frame for main() Frame for fun_1() Frame for fun_2() Memory
Frame for main() Frame for fun_1() Memory #include <stdio.h> void fun_1(void); void fun_2(int); int main() { fun_1(); printf("goodbye goodbye\n"); return 0; } void fun_1(void) int imidate=1; fun_2(imidate); printf("goodbye fun_1\n"); void fun_2(int a) int b = a; Frame for main() Frame for fun_1() Memory
Frame for main() Memory #include <stdio.h> void fun_1(void); void fun_2(int); int main() { fun_1(); printf("goodbye goodbye\n"); return 0; } void fun_1(void) int imidate=1; fun_2(imidate); printf("goodbye fun_1\n"); void fun_2(int a) int b = a; Frame for main() Memory
Function 回傳值
#include <stdio.h> int imin(int, int); int main(void) { int evil1, evil2; printf("Enter a pair of integers (0 0 to quit): "); while(scanf("%d %d", &evil1, &evil2) && !(evil1 == 0 && evil2 == 0)) { printf("The lesser of %d and %d is %d.\n", evil1, evil2, imin(evil1, evil2)); printf("Enter a pair of integers (0 0 to quit): "); } printf("Bye.\n"); return 0; int imin(int n, int m) int min; if (n < m) { min = n; } else { min = m; } return min; 輸出: Enter a pair of integers (0 0 to quit): 300 200 The lesser of 300 and 200 is 200. Enter a pair of integers (0 0 to quit): -8 9 The lesser of -8 and 9 is -8. Enter a pair of integers (0 0 to quit): 0 0 Bye. 範例3-4
輸入兩個整數之後就會用 imin() 來判斷出兩者中較小的數 imin() 的 prototype 宣告成 int imin(int, int); 代表會傳入兩個 int 參數,然後要回傳一個 int。 我們希望回傳值等於傳入參數值中較小的那ㄧ個值,這只要用 if else 就 可以辦到。 在 imin() 的 definition 的最後,必須用 return 把結果傳回 去,在這個範例的寫法就是 return min; 表示要把變數 min 的當時的值 傳回去 在 main() 裡面呼叫 imin(evil1, evil2) 這個 expression 的值會等於 imin() 做完之 後 return 傳回來的值。譬如 imin(5, 3) 的值就等於 3 int imin(int n, int m) { int min; if (n < m) { min = n; } else { min = m; } return min; }
轉型 由於 what_if() 宣告的回傳值型別是 int 雖然 z 是 double,但是在 return 的時候 會被強制轉成 int int what_if(int n) { double z = 100.0/ (double) n; return z; /* what happens? */ } 範例3-5 由於 what_if() 宣告的回傳值型別是 int 雖然 z 是 double,但是在 return 的時候 會被強制轉成 int
return return有一個效果是讓目前的 function 結束,直接跳回到原來呼叫者的 程式碼片段。所以其實return不一定要在程式的最後面 程式最後一行的 printf() 永遠不會被執行。 如果 function 的不需要回傳值 (也就是宣告成 void),那麼也可以用 return; 讓 function 在中途跳回去,寫法就是 return 直接加分號 ; 不傳 回任何值 (因為是 void),只讓 function就此結束執行。 int imin(int n, int m) { if (n < m) return n; else return m; printf("You can't see me.\n"); } 範例3-6 void show_postive(int x) { if (x < 0) return; else printf("%d\n", x); } 範例3-7
Main
#include <stdio.h> int main(void) /* display an integer on screen */ { int num; num = 40; printf("The number is %d.\n", num); return 0; } 範例3-8 C 程式可以看成是許多 functions 的集合 每個 function 會負責某項工作,依照輸入的參數對資料作處理, 然後將結果傳 回 其中最重要的而且一定要包含的 function 就是 main(),它是你的程式的進入點 當你的程式開始執行時,首先就會執行main(),然後在main()裡面再去呼叫其他 functions 在 main() 前面的 int 表示 main() 結束後回傳值 (return value) 的型別是 int, 也就是整數 (integer) 在括號中的 void 表示這個程式的main()在呼叫時不需要傳入任何參數
main的回傳值通常做為判別程式是否正常執行的error code 慣例上,0代表正常,非0的數字代表錯誤或某個狀態 #include <stdio.h> int main(void) /* display an integer on screen */ { int num; num = 40; printf("The number is %d.\n", num); return 0; } main的回傳值通常做為判別程式是否正常執行的error code 慣例上,0代表正常,非0的數字代表錯誤或某個狀態
> ./3-8.exe first second abc main的參數有兩種 void int argc, char * argv[] argc: 紀錄參數的數量 argv: 儲存了每個參數的字串 在console中執行: > ./3-8.exe first second abc 輸出: number of arguments = 4 argv[0] = ./3-8.exe argv[1] = first argv[2] = second argv[3] = abc #include <stdio.h> int main(int argc, char* argv[]) { int i; printf("number of arguments = %d\n", argc); for(i = 0; i < argc; i++) { printf("argv[i] = %s\n", argv[i]); } return 0; 範例3-9
exit 在stdlib.h中有個函式exit,效果是直接離開程式 void exit (int status); status跟main function的return value同義 預設有define EXIT_SUCCESS, EXIT_FAILURE兩個常數 可以在function中呼叫exit,直接結束程式 #include <stdio.h> #include <stdlib.h> void one_or_exit(int x) { if (x == 1) return; else exit(EXIT_FAILURE); } int main(void) int i; one_or_exit(0); return 0;
Scope
Local & Global 依照變數的有效或可見範圍,我們可以把它們劃分成 local variables 和 global variables local:定義在 function 裡面 的變數只有那個 function 可以看得到 global:定義在整個程式最前面,在所有 functions 外面的變數,則是全 部的 functions 都看得到 在命名方面,同一個 scope 裡同一個名字當然不能用兩次譬如 int a; double a; 但是在 function 裡的 local variable 可以和 global variable 同名,這種 情況global variable 在那個 function 裡面會被當作不存在。
上面的例子顯示了變數存在於記憶體的時間長短。 #include <stdio.h> int aa = 100; void f(void) { int aa = 3; printf("f: %d\n", aa++); } int main(void) printf("main: %d\n", aa++); f(); return 0; 輸出: main: 100 f: 3 main: 101 範例3-10 上面的例子顯示了變數存在於記憶體的時間長短。 local variables 只有當 function 被呼叫的時候才會自動出現在記憶體 (stack) 中,而當 function 結束後就不見。 global variables 則是在整個程式執行過程都會一直存在。
static 如何讓 Function 裡面的變數一直存在? 就是在變數的型別前面加上 static 輸出: main: 100 f: 3 如果你想持續記錄某些資料,但是又不想像 global variables 一樣可以 被全部的 functions 隨意修改,就可以用 static variables,只透過某個特 定的 function 來修改。 #include <stdio.h> int aa = 100; int f(void) { static int aa = 3; printf("f: %d\n", aa++); return aa; } int main(void) printf("main: %d\n", aa++); f(); return 0 ; 輸出: main: 100 f: 3 main: 101 f: 4 範例3-11
static (cont.) static global variable & static function 當在一個全域變數或是function的宣告前面加上static,就可以將它 的有效範圍限制在這份程式碼內,也就是有多份程式碼一起編譯時, 存在於其他檔案中的程式無法存取這個變數/function。 static void call() { add(1, 1); } #include <stdio.h> static int add(int a, int b) { return a + b; } int main(void) printf(“1 + 1 = %d\n", add(1, 1)); call(); return 0 ; another.c 範例3-12 main.c 編譯失敗
extern 在一個變數宣告前加上extern,聲明此變數在其他位置(檔案) 被定義。 #include <stdio.h> static int add(int a, int b) { return a + b; } int main(void) extern int a; printf("a = %d", a); return 0 ; int a = 100; another.c 輸出: a = 100 範例3-13 main.c
Appendix
參數列輸入(argc, argv) 要使用參數列輸入,需要在命令提示字元下執行 開始->所有程式->附屬應用程式->命令提示字元 以拖拉方式將程式路徑填入命令提示字元 在路徑後面即可寫入需要的參數
參數列輸入(argc, argv) 以範例3-9為例