<!-- .slide: data-transition="convex-in convex-out" --> # Function ###### tags: `lion_1081` --- <!-- .slide: data-transition="convex-in convex-out" --> # Introduce 1. Scope 2. Lifetime 3. Variable ---- <!-- .slide: data-transition="convex-in convex-out" --> # Scope #### 一個變數能觸及到的範圍 ---- # Lifetime #### 一個變數生存的時間 #### 當變數的lifetime過了,則這個變數就完全無效了 ---- <!-- .slide: data-transition="convex-in convex-out" --> # Variable #### 1. 全域變數(Global variable) #### 2. 區域變數(Local variable) #### 3. 區塊變數(Block variable) ---- <!-- .slide: data-transition="convex-in convex-out" --> ## 全域變數 Global variable ```c= #include<stdio.h> int A = 1; //Global variable int main(void){ // statment return 0; } ``` - 在整個程式之中都能看到它的存在,且可以呼叫使用 - Lifetime 始於程式開始,終止於程式結束 - 初學者不建議使用,除非必要 ---- <!-- .slide: data-transition="convex-in convex-out" --> ## 區域變數 Local variable ```c= #include<stdio.h> int main(void){ int B = 10; //Local variable printf("B = %d\n", B); return 0; } ``` - 只能在該函式內使用,其他函式不可使用該變數 - Lifetime 始於函式被呼叫後,止於函式執行完畢 ---- <!-- .slide: data-transition="convex-in convex-out" --> ## 區塊變數 Block variable ```c= #include<stdio.h> int main(void){ int i; // Local variable for( i = 0; i < 5; ++i) { int B = 0; //Block variable ++B; printf("B = %d\n", B); } return 0; } ``` - 只有該區塊內可使用 - Lifetime 始於該區塊開始之時,終止於該區塊結束 - hint: -std=c99 ---- <!-- .slide: data-transition="convex-in convex-out" --> ```c= #include<stdio.h> int A = 1; //Global variable int main(void){ int B = 10; //Local variable for(B = 0; B < 5; ++B) { int C = 0; //Block variable ++C; printf("C = %d\n", C); } printf("A = %d\n", A); printf("B = %d\n", B); return 0; } ``` --- <!-- .slide: data-transition="convex-in convex-out" --> # So, what is function? ---- <!-- .slide: data-transition="convex-in convex-out" --> # 一個簡單的範例 ## A+B=C, print C ---- <!-- .slide: data-transition="convex-in convex-out" --> ## 在學習function之前,你可能會寫成這樣 ```c= #include<stdio.h> int main(){ int a, b, c; scanf("%d%d", &a, &b); c = a + b; printf("%d\n", c); } ``` #### or ```c= #include<stdio.h> int main(){ int a, b; scanf("%d%d", &a, &b); printf("%d\n", a + b); } ``` ---- <!-- .slide: data-transition="convex-in convex-out" --> ## 寫成function就像 ```clike= int add(int A, int B){ int C; C = A + B; return C; } ``` ---- <!-- .slide: data-transition="convex-in convex-out" --> # 那寫成一個可執行的code 會長怎樣? ---- <!-- .slide: data-transition="convex-in convex-out" --> ```clike= #include<stdio.h> int add(int A, int B){ int C; C = A + B; return C; } int main(){ int a, b, c; scanf("%d%d", &a, &b); c = add(a, b); printf("%d\n", c); } ``` ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Line 2: ![Imgur](https://i.imgur.com/uZ64b7R.png) ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Line 2(cont.): - 回傳的 type 可以是所有的 type + void - void 表示說 該function不會回傳任何東西 ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Line 3~5: ![Imgur](https://i.imgur.com/oGYBacc.png) ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Line 3~5(cont.): - function中的return statement一定要和function的return type一樣 - 這裡的A的type是int,但這裡強制轉為char回傳 ```clike= char func(int A){ return A; } int main(){ int a = 97; printf("%c\n", func(a)); } ``` ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Line 10: ![Imgur](https://i.imgur.com/0MdC0mg.png) ---- <!-- .slide: data-transition="convex-in convex-out" --> ![Imgur](https://i.imgur.com/0WXl9Zb.png =600x) ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Practice 1: - Make a main & power function - main function do the input and output - power function do x(input 1) to the power of n(input 2), then return to the main function ---- <!-- .slide: data-transition="convex-in convex-out" --> # [ANS](https://github.com/NightKirie/lion2017/blob/master/function/practice1.c) ---- <!-- .slide: data-transition="convex-in convex-out" --> ## 你也可以寫成這樣 ```c= #include<stdio.h> int main(){ int a, b; scanf("%d%d", &a, &b); printf("%d\n", add(a, b)); } ``` ---- ```c= #include<stdio.h> // 從A加總到B int func(int A,int B){ int i,sum=0; for(i=A;i<=B;++i){ sum += i; } return sum; } int main(){ int a, b, c; a = func(2,8); b = func(4,12); c = func(5,13); printf("%d %d %d\n", a, b, c); } ``` ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Conclusion of Function |優點|缺點| |:-|:-| |1.可讀性提高|1. 使用更多的記憶體空間| |2. 較容易維護|2. 型別問題| |3. 可重複使用|| ---- ```clike= #include<stdio.h> int add(int A, int B){ // A,B are parameters int C; C = A + B; return C; } int main(){ int a, b, c; scanf("%d%d", &a, &b); c = add(a, b); // a,b are arguments printf("%d\n", c); } ``` <!-- .slide: data-transition="convex-in convex-out" --> - parameter 和 argument 可以使用相同的名字 (在 call by value 的時候,仍為不同的東西) - 我們通常會把<font color="cyan"> parameter</font> 叫做<font color="cyan"> "formal parameter" </font>,把 <font color="lime">argument</font> 叫做 <font color="lime">actual parameter"</font> ---- - Actual parameter 可以是一個 <font color="cyan">constant</font> (ex. 4), 一個 <font color="cyan">variable</font> (ex. x), 或甚至是一個 <font color="cyan">expression</font> (ex. x+y) - 當你在使用任何變數時,請注意一下他是屬於哪種 scope ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Practice 2: - make a main function to input (a,b,c) of an quadratic equation $ax^2+bx+c$, - then make a function to calculate the quadratic formula, - in the end, return the biggest answer to main function to output it - hint: use <math.h> & sqrt() & gcc -o xxx xxx.c -lm ---- <!-- .slide: data-transition="convex-in convex-out" --> - Bonus 1: add judgement if it's real number, print the error message if not - Bonus 2: make this code in loop until input is EOF ---- <!-- .slide: data-transition="convex-in convex-out" --> # [Ans](https://github.com/NightKirie/lion2017/blob/master/function/practice2.c) --- <!-- .slide: data-transition="convex-in convex-out" --> ## Call by value & address ---- ### Call by value <!-- .slide: data-transition="convex-in convex-out" --> ```clike= #include<stdio.h> void add(int a){ ++a; } int main(){ int a = 1; add(a); printf("%d\n", a); } ``` - print out 1 ---- ### call by value ### 就是把 **值** 複製給對方 | 執行前| main的a | add的a| 執行後| main的a | add的a | | -------- | -------- | --------|-------- | -------- | -------- | |value|1|1|value|1|2| |address|0x04|0x16|address|0x04|0x16| ---- <!-- .slide: data-transition="convex-in convex-out" --> ### Call by address ```clike= #include<stdio.h> void add(int* a){ ++(*a); } int main(){ int a = 1; add(&a); printf("%d\n", a); } ``` - print out 2 ---- #### &a 表示取得 a 的位址 #### * a 表示取得對應這個位址的值 | 執行前| main的a | add的a| 執行後| main的a | add的a | | -------- | -------- | --------|-------- | -------- |-------- | |value|1|0x04|value|2|0x04| |address|0x04|0x16|address|0x04|0x16| #### add的\*a 就是 main的a的值 --- ## 如何把array傳進function呢 ? ---- - 當傳進一個array時 - argument就是array的名字 - parameter的大小必須要和原本的array一樣 ---- <!-- .slide: data-transition="convex-in convex-out" --> #### 1-D array ```clike= #include<stdio.h> //void add_one(int *A) //void add_one(int A[]) void add_one(int A[5]){ int i; for(i = 0; i < 5; i++) printf("%d\n", ++A[i]); } int main(){ int a[5] = {0,1,2,3,4}; add_one(a); } ``` ---- <!-- .slide: data-transition="convex-in convex-out" --> #### 2-D array ```clike= #include<stdio.h> //void add_one(int A[][3]) void add_one(int A[2][3]){ int i,j; for(i = 0; i < 2; i++) for(j = 0; j < 3; j++) printf("%d\n", ++A[i][j]); } int main(){ int a[2][3] = {{0,1,2},{4,5,6}}; add_one(a); } ``` ---- ## Practice 3: - Make a main & "multi" function - Inside main function, make a array can store 10 integer, the elements are 1 to 10 - Using the "multi" function to calculate the multiplication of this 10 elements and print it out ---- <!-- .slide: data-transition="convex-in convex-out" --> # [ANS](https://github.com/NightKirie/lion2017/blob/master/function/practice3.c) ---- <!-- .slide: data-transition="convex-in convex-out" --> - 當傳進一個n維array A[a][b][c]....[n], - 在a已知的前提下,parameter必須宣告一個至少像B[][b][c].....[n]的陣列 - 因為電腦會把n維轉成1維,並將它存在1維address中 - Ex. 2-D array int a[3][4] - => (i x 4 + j) x 4 bytes + a[0][0]'s address = a[i][j]'s address ---- <!-- .slide: data-transition="convex-in convex-out" --> ```clike= #include<stdio.h> void add_one(int A[3][4]){ for(int i = 0; i < 3; i++) for(int j = 0; j < 4; j++) printf("%d\n%p\n", ++A[i][j], &A[i][j]); } int main(){ int a[3][4] = {{0,1,2,3}, {4,5,6,7}, {8,9,10,11}}; add_one(a); } ``` - A[i][j] 與 A[i][j+1] 兩address之間相差 4 bytes - A[i][3] 與 A[i+1][0] 兩address之間也相差 4 bytes ---- <!-- .slide: data-transition="convex-in convex-out" --> ## array 是 call by address <!-- .slide: data-transition="convex-in convex-out" --> ```clike= #include<stdio.h> void add_one(int A[3][4]){ for(int i = 0; i < 3; i++) for(int j = 0; j < 4; j++) ++A[i][j]; } int main(){ int a[3][4] = {{0,1,2,3}, {4,5,6,7}, {8,9,10,11}}; add_one(a); for(int i = 0; i < 3; i++) for(int j = 0; j < 4; j++) printf("%d\n", a[i][j]); } ``` print: 1~12 ---- <!-- .slide: data-transition="convex-in convex-out" --> - 當我們在傳一個array的時候,我們實際上是傳進該array第一個element的address - 也就是說,add_one(a)的a就是array中第一個element的address ```clike= #include<stdio.h> //void add_one(int* A) void add_one(int A[3][4]){ printf("address of A[3][4] is %p\n", &A[0][0]); printf("address of A is %p\n", A); //in this function, A is a pointer } int main(){ int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11}; add_one(a); printf("address of a is %p\n", a); printf("address of a[0][0] is %p\n", &a[0][0]); } ``` - **所以說,array 是一種 pointer** --- <!-- .slide: data-transition="convex-in convex-out" --> ## Supplements ---- <!-- .slide: data-transition="convex-in convex-out" --> ## Forward declaration ---- <!-- .slide: data-transition="convex-in convex-out" --> ```clike= #include<stdio.h> int add(int, int); int main(){ int a, b, c; scanf("%d%d", &a, &b); c = add(a, b); printf("%d\n", c); } int add(int A, int B){ int C; C = A + B; return C; } ``` - 可以把第二行刪掉,看看compile後的訊息 ---- <!-- .slide: data-transition="convex-in convex-out" --> - 那我們如何寫forward declaration? - 你只需要宣告 function return type, function name, and parameter type - 建議 : forward declaration的順序跟function的先後順序一樣,從上到下排列 ---- <!-- .slide: data-transition="convex-in convex-out" --> ## return & exit - hint: <stdlib.h> ---- <!-- .slide: data-transition="convex-in convex-out" --> ```clike= #include<stdio.h> #include<stdlib.h> void test(); int main(){ printf("main start\n"); test(); printf("main end\n"); } void test(){ printf("inside test\n"); return; //exit(1); } ``` ---- <!-- .slide: data-transition="convex-in convex-out" --> - 使用exit,程式會在讀到exit的時候結束 - return則是從一個function中返回,並將控制權給使用該function的function - e.g.從test返回,並把控制權給main ---- - 我們可以在terminal上使用"echo $?"來看上一個執行的指令所回傳的值 - exit(0) 代表程式正常結束 - exit(<非零>)則表示程式異常終止
{"metaMigratedAt":"2023-06-15T00:38:58.495Z","metaMigratedFrom":"Content","title":"Function","breaks":true,"contributors":"[{\"id\":\"8329238d-0a43-44c6-9d21-cb0bdf1001b8\",\"add\":19665,\"del\":8199}]"}
    988 views