# 嘉科實中社團講義(113第1學期) | 周次 | 日期 | 課程大綱| | ---- | ---------- |-------| 1|2024/09/27|課程安排、電腦運作原理、程式語言介紹、C語言小程式| 2|2024/10/04|資料型態、輸入與輸出、算術邏輯運算、條件判斷| 3|2024/10/18|條件判斷(switch、三元運算子)、迴圈(for)| 4|2024/11/08|迴圈(while、do-while)、陣列| 5|2024/11/15|字元陣列、二維陣列、APCS題目練習| 6|2024/12/20|APCS題目練習| 7|2024/01/03|練習APCS題目| ## 2024/09/27 ### 今日目標 * 決定上課方向(APCS+Python應用程式 或 全APCS) * 了解電腦和程式運作原理 * 可以完成C語言程式(完成輸出Hello world) --- ### APCS介紹 [APCS大學程式設計先修檢測](https://apcs.csie.ntnu.edu.tw/) [113學年度大學申請入學招生各校系篩選標準一覽表](https://www.cac.edu.tw/CacLink/apply113/113applY_xSievePk4g_T43D54VO_91S/html_sieve_113_Ks7Zx/Standard/collegeList.htm) --- ### 電腦運作原理 > CPU、記憶體、硬碟 ??? 電腦認識的0101又是??? #### 馮諾伊曼架構(Von Neumann) 馮諾伊曼架構是目前大多數電腦的都是基於它來進行設計,主要可以分為: `輸入/輸出設備`、`控制單元`、`算術邏輯單元`、`記憶單元`。 ![image](https://hackmd.io/_uploads/r1WtLJXCC.png) 圖片來源 : [Von_Neumann_Architecture By Kapooht ](https://zh.wikipedia.org/zh-tw/%E5%86%AF%E8%AF%BA%E4%BC%8A%E6%9B%BC%E7%BB%93%E6%9E%84#/media/File:Von_Neumann_Architecture.svg) ##### 輸入/輸出設備(I/O Device) - 用於將資料輸入到電腦的稱為輸入設備。 如: 滑鼠、鍵盤... - 而將資料經電腦處理後呈現出來的稱為輸出設備。 如: 螢幕、印表機... > 還能舉例有哪些嗎? ##### 中央處理單元(CPU) `中央處理單元` = `控制單元` + `算數邏輯單元` ##### 控制單元(CU) 負責從`記憶單元`中取得指令,解讀指令後並控制系統其他部分來執行指令 ##### 算術邏輯單元(ALU) 負責進行數學、`邏輯運算`(之後會介紹) ##### 記憶單元 負責儲存資料、程式指令的地方。記憶體又可以區分為`主記憶體`、`輔助記憶體` - `主記憶體`用來存放能讓CPU快速處理的資料,如: 記憶體 - `輔助記憶體`用來儲存需要長期存放的資料,如: 硬碟 > 哪種速度比較快? > 哪種容量會比較大? > 硬碟、記憶體差在哪裡? :::spoiler 答案 主記憶體的速度比較快。 輔助記憶體的容量較大。 電源關閉後記憶體內容會消失,稱為`揮發性記憶體`;電源關閉後硬碟內容並不會消失,稱為`非揮發性記憶體`。 ::: ::: info `馮諾伊曼瓶頸`指CPU的執行速度高於CPU從記憶體讀取指令的速度造成效能的限制,解決方法之一是在CPU與記憶體之間設計一個`快取記憶體(Cache)`,CPU要執行指令時先從`快取`裡面抓取。 ::: --- ### 十進制與二進制 > 大家平常所使用的數字為十進制,而電腦的世界中只有`0/1`這兩種選擇,儲存在記憶體中的資料也都是`0/1`,所以電腦所採取的是`二進制` #### 十進制 5201314 = | |10^6^ | 10^5^ | 10^4^ | 10^3^ | 10^2^ | 10^1^ | 10^0^| |:---------:|---:|---:|---:|---:|---:|---:| ---:| | 十進位值 | 5 | 2 | 0 | 1 | 3 | 1 |4 | 5201314 = 5 * 10^6^ + 2 * 10^5^ + 0 * 10^4^ + 1 * 10^3^ + 3 * 10^2^ + 1 * 10^1^ + 4 * 10^0^ #### 二進制 | | 2^5^ | 2^4^ | 2^3^ | 2^2^ | 2^1^ | 2^0^ | |:---------:|---:|---:|---:|---:|---:|---:| | 二進位值 | 1 | 1 | 0 | 1 | 0 | 0 | (110100)<sub>2</sub> = (1 * 2^5^ + 1 * 2^4^ + 0 * 2^3^ + 1 * 2^2^ + 0 * 2^1^ + 0 * 2^0^)<sub>10</sub> = (52)<sub>10</sub> > 試試看 (87)<sub>10</sub> = (?)<sub>2</sub>,(164)<sub>10</sub> = (?)<sub>2</sub> :::spoiler 答案 (87)<sub>10</sub> = (1010111)<sub>2</sub> (164)<sub>10</sub> = (10100100)<sub>2</sub> ::: --- ### 程式語言介紹 > 程式就是一連串的指令來完成我們想要的工作,而程式語言就是用來寫出一連串的指令,不同的程式語言用途也不太一樣 - C: 開發與底層(硬體)相關的程式 如: 驅動程式、開發作業系統 - Java: 可用於寫遊戲(Minecraft)、手機應用程式、網頁後端 - Python: 應用廣泛,如: 開發AI程式、資料分析、網頁後端 #### 低階/高階程式語言??? > 所謂的高階/低階並不是指好或不好,而是以是否接近硬體的語言來區分 - 低階程式語言為較近硬體的語言,如: `Assembly` - 高階程式語言較接近人類的語言,如: 大部分的程式語言(`C`、`Python`、`Java`...) >下圖Assembly寫的Hello World!,由ChatGPT撰寫 ![image](https://hackmd.io/_uploads/ryUY2l70R.png) >下圖C語言寫的Hello World!,由ChatGPT撰寫 > ![image](https://hackmd.io/_uploads/HyfchxQRA.png) #### 電腦怎麼看得懂程式??? > 電腦要看的懂程式需要藉由編譯器或直譯器,將撰寫好的程式語言翻譯成電腦看得懂的語言 ##### 編譯式語言?直譯式語言? * `編譯式語言`會藉由`編譯器`翻譯,一次會翻譯一整個程式,通常會產生一個新的檔案,要使用的時候是直接執行翻譯好的檔案。如: `C` * `直譯式語言`會藉由`直譯器`翻譯,會一邊進行翻譯一邊執行程式,所以要執行程式的時候還需要再進行翻譯。如: `Python` > 哪一種執行效率會比較高? :::spoiler 答案 編譯式語言 ::: --- ### 第一支C語言 > 在寫C語言之前需要先去下載可以用來開發的環境,本課程會以`Dev C++`為例。 [Orwell Dev-C++ 5.11 免安裝中文版 - 免費C/C++語言程式設計工具](https://www.azofreeware.com/2006/03/dev-c-50-beta-92-4992.html) 打開Dev C++ 後請建立新專案,並把下方程式碼貼到Dev C++中 ```c #include <stdio.h> int main(){ printf("Hello World!\n"); return 0; } ``` 之後請進行編譯,編譯完成後再執行看到下方結果後,恭喜你完成了你的第一隻程式 ![image](https://hackmd.io/_uploads/S1klVZQA0.png) ---- ### 重點整理 * 馮諾伊曼架構的五大單元: `輸入/輸出設備`、`控制單元`、`算術邏輯單元`、`記憶單元`。 * 電腦採用的是二進制,所以電腦只認識0/1 * 低階程式語言較接近機器的語言,而高階程式語言較接近人類語言 * 程式語言需要經過編譯器或直譯器翻譯 --- ### 推薦學習資源 * [Feis Studio C語言入門教學](https://www.youtube.com/watch?v=yWPGumB64tM&list=PLY_qIufNHc293YnIjVeEwNDuqGo8y2Emx&index=1) * C語言教學手冊(四版) 作者: 洪維恩 * Foundations of Computer Science 作者: Forouzan * [AP325](https://drive.google.com/drive/folders/10hZCMHH0YgsfguVZCHU7EYiG8qJE5f-m) 作者: 吳邦一 --- ### 參考資料 * [電腦運作原理](https://hackmd.io/@howkii-studio/apcs_overview/https%3A%2F%2Fhackmd.io%2Fo7B-a1u-TdKFuNQsgtVYMg) * [【Lynn 寫點科普】你知道記憶體跟硬碟有什麼不同嗎?又有哪些種類呢?](https://www.inside.com.tw/article/9595-dram) * [6.1 程式語言中有社會階級?](https://docs.f5ezcode.in/cs-basic/di-liu-zhang-gao-xin-de-tong-mi-cheng-shi-yan/6.1-yan-you-gao-fu) ## 2024/10/04 ### 今日目標 * 了解C語言變數型態有哪些 * 變數的概念 * C語言輸入與輸出 * 數值、布林運算 * 條件判斷(if) --- ### C語言變數型態 > 在C語言裡面要宣告變數都需要先指定型態,下面的表列出了常用的型態. |型別|C語言表示法|格式化字串表示法|佔幾個位元組(byte)|值的範圍| |---|---------|-------------|---------------|---------- |整數|short|%hd|2|-2^15^~2^15^-1| ||int|%d|4|-2^31^~2^31^-1| ||long long|%lld|8|-2^63^~2^63^-1| |浮點數|float|%f|4|2.939x10^−38^~3.403x10^38^| ||double|%lf|8|5.563x10^−309^~1.798x10^308^| |字元|char|%c|1|-2^7^~2^7^-1| 參考自:[資料型態 (C語言)](https://zh.m.wikipedia.org/zh-tw/%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B_(C%E8%AF%AD%E8%A8%80)) > 想想看位元組大小跟值的範圍有何關係? --- ### 變數 > 變數簡單來說就是`用一個名稱來存放可能會變動的數值` ``` 變數名稱 money 記憶體位址 0x0001 |---------| 數值 | 30 | |---------| ``` 變數在記憶體內的存放方式(Big-Endian) ``` 變數名稱 money 記憶體位址 0x0001 0x0002 0x0003 0x0004 |----------|---------|----------|----------| 記憶體 | 00000000 | 00000000 | 00000000 | 00011110 | |----------|---------|----------|----------| ``` #### C語言變數宣告 > C語言要使用任何變數都要先經過宣告,Python則不需要 ```c 變數型態 變數名稱 變數值 int money = 30 float height = 167.8 char ch = 'A' int* money_ptr = &money = 0x0001 ``` #### 指標變數 > 指標是入門C語言的大大魔王!是C裡面很重要的概念,指標變數簡單來說`存放的是記憶體位址` 使用範例: `&`是取址符號,用來取出變數的記憶體位址 ```c int money = 10; int* money_ptr = &money; // money_ptr變數存的是money變數的記憶體位址 printf("money = %d = %d\n", money, *money_ptr); printf("money_ptr = %p = %p\n", &money, money_ptr); ``` --- ### 輸入與輸出 #### 輸出 變數型態的格式化字串求參考上面的表 ```c //如果沒有要輸出變數 printf("要輸出的字串"); //如果要輸出變數 printf("變數型態的格式化字串",變數名稱); ``` 使用範例: ```c //如果沒有要輸出變數 printf("Hello, World!\n"); // \n代表的是換行 //如果要輸出變數 int money = 30; printf("我剩下%d元\n",money); ``` #### 輸入 變數型態的格式化字串求參考上面的表 ```c // !請注意變數名稱一定要加上& ! scanf("變數型態的格式化字串",&變數名稱); ``` 使用範例: ```c int money; float height; printf("你剩下多少錢:"); scanf("%d",&money); printf("你身高多高:"); scanf("%f",&height); printf("我有%d元,我身高%f公分\n",money,height); ``` --- ### 數值運算和邏輯運算 #### 數值運算 |符號|用途|範例|備註| |---|---------|-------------|----| |+|加法|5+2 = 7|| |-|減法|5-2 = 3|| |*|乘法|5+2 = 7|| |/|除法|5/2 = 2|**整數相除結果還是整數(捨去)**| |%|取餘數|5%2 = 1|5/2 = 2...1| 使用範例: ```c float var1 = 5/2; float var2 = 5.0/2; // 5/2.0 或 5.0/2.0 也會得到相同結果 printf("var1 = %f, var2 = %.1f", var1, var2); // 輸出結果: var1 = 2, var2 = 2.5 // %.1f 代表我只要輸出到小數點後1位 int age = 18; age = age + 1; // 等同於 age += 1 printf("age = %d\n",age); //輸出結果: age = 19, printf("age++ = %d\n",age++); //輸出結果: age = 19, 先執行完printf再把age = age+1, 所以現在age = 20 printf("++age = %d\n",++age); //輸出結果: age = 21, 先執行age = age+1再執行printf, ; ``` 實做題練習: > 請實作出一個讓使用者輸入半徑並可以計算出圓面積和圓周長的程式 **(請輸出到小數點後兩位)**. (pi = 3.14) > 範例輸入: 5 > 範例輸出: 圓面積 = 78.50, 圓周長 = 31.40 :::spoiler 參考解答 ```c #include <stdio.h> int main(){ int r; float pi = 3.14; scanf("%d",&r); printf("圓面積 = %.2f, 圓周長 = %.2f",pi*r*r, 2*pi*r); return 0; } ``` ::: 選擇題練習: > 請選出程式的執行結果為何? - 10 - 10.5 - 11 ```c int var1 = 10; int var2 = ++var1; printf("%d\n",(var1+var2)/2); ``` :::spoiler 參考解答 ```C 執行 int var2 = ++var1 的步驟為: 1. var1 = var1 + 1; //所以var1 = 11 2. var2 = var1; //所以var2 = 11 最後 (var1+var2)/2 = 11 答案為: 11 ``` ::: #### 邏輯運算 > 可以把`1`當作`TRUE`,`0`當作`FALSE` AND且 `&&` > 兩條件都是1結果就是1 假設: ``` 我喜歡他 = 1, 我不喜歡他 = 0 他喜歡我 = 1, 他不喜歡我 = 0 我們會在一起 = 1, 我們不會在一起 = 0 ``` 舉例: ``` 如果我喜歡他(條件1) 且 他也喜歡我(條件2) -> 我們就會在一起(結果) ``` |條件1|條件2|結果|舉例| |---|----|----|-----------| |1|0|0|我喜歡他,他不喜歡我 -> 我們不會在一起 :(| |0|1|0|我不喜歡他,他喜歡我 -> 我們不會在一起 :(| |0|0|0|我不喜歡他,他也不喜歡我 -> 我們不會在一起 :(| |1|1|1|我喜歡他,他也喜歡我 -> 我們會在一起 :)| OR或 `||` > 兩條件其中一個是1結果就是1 假設: ``` 我有撐傘 = 1, 我沒有撐傘 = 0 我有穿雨衣 = 1, 我沒穿雨衣 = 0 我會被淋濕 = 1, 我不會被淋濕 = 0 ``` 舉例: ``` 如果我有撐傘(條件1) 或 我有穿雨衣(條件2) -> 我就不會被淋濕(結果) ``` |條件1|條件2|結果|舉例| |---|----|----|-----------| |1|0|1|我有撐傘,沒穿雨衣 -> 我不會被淋濕 :)| |0|1|1|我沒有撐傘,有穿雨衣 -> 我不會被淋濕 :)| |0|0|0|我沒有撐傘,沒穿雨衣 -> 我會被淋濕 :(| |1|1|1|我有撐傘,有穿雨衣 -> 我不會被淋濕 :)| NOT非 ``!`` > 類似於相反的概念 |輸入|結果| |---|----| |1|0| |0|1| 使用範例: ```c int a = 1; int b = 0; int ans = !(a&&(b||a)); // b||a => 0||1 = 1 // a&&(b||a) => 1||1 = 1 // !(a&&(b||a)) => !(1) = 0 printf("%d\n",ans); //輸出結果: 0 ``` 選擇題題目範例1: > 請問ans的輸出結果為何? ```c int a = 0; int b = 0; int ans = ( (!a || b) && !(!b && a)); printf("%d\n",ans); ``` :::spoiler 參考答案 ```c (!a || b) => (1 || 0) = 1 !(!b && a) => !(1 && 0) => !0 => 1 (!a || b) && !(!b && a) => 1 && 1 = 1 答案為: 1 ``` ::: 選擇題練習: > 若ans的輸出要為 1,則a、b不能選下列哪一種組合? - a = 1, b = 0 - a = 0, b = 1 - a = 1, b = 1 - a = 0, b = 0 ```c int a; int b; int ans = !(!a&&b); printf("%d\n",ans); ``` :::spoiler 參考答案 ```c 答案為: 不能選 a = 0, b = 1 ``` ::: #### 關係運算子 > 用於比較數值,若成立則為1;否則為0。 |符號|用途|範例| |---|----|----| |>|大於| 5>4 => 1| |>=|大於等於| 5>=4 => 1| |<|小於|5<4 => 0| |<=|小於等於| 5<=4 => 0| |==|等於|5==4 => 0| |!=|不等於|5!=4 => 1| 使用範例: ```C int a = 5; int b = 4; printf("%d > %d => %d\n",a ,b ,a>b); printf("%d >= %d => %d\n",a ,b ,a>=b); printf("%d < %d => %d\n",a ,b ,a<b); printf("%d <= %d => %d\n",a ,b ,a<=b); printf("%d == %d => %d\n",a ,b ,a==b); printf("%d != %d => %d\n",a ,b ,a!=b); ``` 選擇題練習: > 請問ans的輸出結果為何? ```c int a = 5; int b = 10; int ans = !(a>b) && (a<b); printf("%d\n",ans); ``` :::spoiler 參考答案 ```c !(a>b) => !(5>10) => 1 (a<b) => 1 !(a>b) && (a<b) => 1 && 1 => 1 答案為: 1 ``` ::: --- ### 條件敘述(If) > 需要用到條件判斷時就會使用到`If`, `else`和`else if`必須要搭配`If` 使用範例 如果`if`的條件判斷結果為1的話,就會執行他下方的程式,若`if`的條件判斷結果為0,會往下到`else if`再進行判斷,若結果都為0,最後則會執行`else`裡面的程式。 ```C if(條件判斷){ ...某些程式... } else if(其他條件判斷){ ...某些程式... } else{ ...某些程式... } ``` ```C int a = 10; int b = 6; int c = 1; int d = 5; if(a<b){ printf("a<b\n"); if(c>d){ printf("c>d\n"); } else{ printf("c<=d\n"); } } else if(a>b){ printf("a>b\n"); if(c>d){ printf("c>d\n"); } else{ printf("c<=d\n"); } } else{ printf("a==b\n"); } // 輸出結果: a>b // c<=d ``` 實作題練習: > 請實作出一個讓使用者輸入年份並可以判斷是閏年或平年。 > 閏年規則請參考 : [閏年 - 維基百科,自由的百科全書](https://zh.m.wikipedia.org/zh-tw/%E9%97%B0%E5%B9%B4) > 範例輸入: 2020 > 範例輸出: 閏年 :::spoiler 參考解答 ```C #include <stdio.h> int main(){ int year; scanf("%d",&year); if(year%4 == 0){ if(year%100 == 0){ if(year%400 == 0){ printf("閏年\n"); } else{ printf("平年\n"); } } else{ printf("閏年\n"); } } else{ printf("平年\n"); } return 0; } ``` ::: --- ### 學習資源 - [高中生程式解題系統](https://zerojudge.tw) - [APCS 觀念題資源分享](https://hackmd.io/@apcser/B1N5GYEto) 作者: APCSer --- ## 2024/10/18 ### 今日目標 * 複習10/04課程 * 條件判斷(switch、三元運算子) * 迴圈(for、while、do-while) * 陣列介紹 --- ### 複習題目 選擇題練習1 > 下方程式碼執行完成後,var2為多少? ```c int var1 = 6, var2 = 4; var2 += var1++; var2 += var1; printf("%d\n",var2); ``` * 選項A : 17 * 選項B : 10 * 選項C : 15 :::spoiler 參考解答 ```c var2 += var1++ => 1. var2 = var2 + var1; //10 => 2. var1 = var + 1; //7 var2 += var1 => var2 = var2 + var1; // 17 答案為: 選項A ``` ::: 選擇題練習2 >以下程式能否將var1和var2的數值互換? ```c int var1 = 5, var2 = 4; var1 = var2; var2 = var1; printf("var1 = %d, var2 = %d\n",var1, var2); ``` :::spoiler 參考解答 不可以,正確解答的交換程式如下。 ```c int var1 = 5, var2 = 4, temp; temp = var1; var1 = var2; var2 = temp; printf("var1 = %d, var2 = %d\n",var1, var2); ``` ::: --- ### 條件判斷(switch) > 除了上禮拜教的`If`之外,`switch`也會被用來條件判斷 #### 使用範例 `switch(數值)`裡面的數值可以是變數或是運算式,如果`switch`裡面數值符合`判斷數值`或`判斷區間`的話就會**往下執行直到碰到`break`**,若沒有符合的`case`則會執行`default`內的程式。 ```c switch(數值){ case 判斷數值1: . . . break; case 判斷數值2: . . . break; case 判斷區間1 ... 判斷區間2: . . . break; case 判斷數值n: . . . break; default: . . . break; } ``` ##### 正常版 ```c int a = 10; switch(a){ case 8: printf("a是8\n"); break; case 9: printf("a是9\n"); break; case 10: printf("a是10\n"); break; default: printf("都不符合\n"); break; } /* 輸出: a是10 */ ``` ##### 奇怪版(沒有break) ```c int a = 10; switch(a){ case 8: case 9: printf("a是8或是9\n"); break; case 10: printf("a是10\n"); case 11: printf("a是11\n"); default: printf("都不符合\n"); break; } /* 輸出: a是10 a是11 都不符合 * / ``` --- ### 三元運算子 ~~要讓別人看不懂程式碼的時候可以用~~ #### 使用範例 ```c 條件式 ? 條件為真要做的事情 : 條件為假要做的事情 ``` ```c int number = 7; number % 2 == 0 ? printf("偶數\n") : printf("奇數\n"); ``` 等同於下方的寫法 ```c int number = 7; if(number % 2 == 0){ printf("偶數\n"); } else{ printf("奇數\n"); } ``` ```c int number = 7; number = number % 2 == 0 ? number + 2 : number + 1; ``` 等同於下方的寫法 ```c int number = 7; if(number % 2 == 0){ number = number + 2; } else{ number = number + 1; } ``` --- ### 迴圈判斷(for) > 當我們需要**重複做結構相似**的事情時我們就會需要使用迴圈,如: 輸出10次「Hello, World!」 #### 使用範例 `第一輪要執行的程式`通用來設定迴圈變數的初始值,每次迴圈開始時會檢查`判斷式`是否為`真(1)`,若為`假(0)`則跳出迴圈,每做完一輪就會執行`做完一輪要執行的程式`通常是用來更新迴圈變數 ```c for(第一輪要執行的程式;判斷式;做完一輪要執行的程式){ . . . } ``` ```c int i; for(i = 0;i<10;i++){ printf("%d: Hello, World!\n",i); } printf("i = %d",i); ``` 等同於下面的寫法 ```c int i = 0; for(;i<10;){ printf("%d: Hello, World!\n",i); i++; } printf("i = %d",i); ``` 若碰到`break`則會跳出迴圈 ```c int i; for(i = 0;i<10;i++){ if(i == 5){ break; } printf("%d: Hello, World!\n",i); } printf("i = %d",i); ``` ##### 巢狀for迴圈 ```c int i, j; for(i = 0;i<10;i++){ printf("i = %d\n", i); for(j=0;j<10;j++){ printf("%d ",j); } printf("\n"); } ``` 實作題練習 > 請使用`巢狀迴圈`寫出九九乘法表 輸出結果如下圖: ![image](https://hackmd.io/_uploads/HJs4lO6y1g.png) :::spoiler 解答 ```c #include <stdio.h> int main(){ int i, j; for(i = 1;i<10;i++){ for(j = 1;j<10;j++){ printf("%d * %d = %d\t",j, i, j*i); } printf("\n"); } } ``` ::: 選擇題題目範例 > 下方的程式碼的功能為求出第10項的費波那契數列的值(F_0 = 0,F_1 = 1, ... F_10 = 55),要將下列哪個程式碼插入到指定處才可以把這隻程式完成 > [費波那契數 - 維基百科](https://zh.wikipedia.org/zh-tw/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0) ```c #include <stdio.h> int main(){ int a_0 = 0, a_1 = 1, a_n; int i, n = 10; > 程式碼插入處 printf("F_%d = %d\n",n, a_n); } ``` * 選項A ```c for(i = 2; i<=n ;i++){ a_n = a_0 + a_1; a_0 = a_n; a_1 = a_0; } ``` * 選項B ```c for(i = 2; i<n+1 ;i++){ a_n = a_0 + a_1; a_0 = a_1; a_1 = a_n; } ``` * 選項C ```c for(i = 2; i<n ;i++){ a_n = a_0 + a_1; a_0 = a_1; a_1 = a_n; } ``` :::spoiler 參考解答 ```c 答案為: 選項B ``` ::: --- ## 2024/11/08 ### 今日目標 * 複習前幾周的課程 * 迴圈(while、do-while) * 陣列 --- ### 迴圈判斷(while、do-while) > 也是迴圈的一種,通常是用在不確定會執行幾次 #### 使用範例 當`判斷式`運算結果為`真(1)`,則會執行裡面的程式**直到判斷式為`假(0)`** ```c while(判斷式){ . . . } ``` ```c int i = 10; while(i>0){ printf("%d: Hello, World!\n",i); i--; } printf("i = %d\n",i); ``` 若碰到`break`一樣會跳出迴圈 ```c int i = 10; while(i>0){ if(i == 5){ break; } printf("%d: Hello, World!\n",i); i--; } printf("i = %d\n",i); ``` `do-while`第一次先做`do`裡面的程式碼,下一輪再去判斷`while`的判斷式是否為真。 與`while`的差別為`do-while`**至少會執行一次裡面的程式碼** ```c int i = 10; do{ printf("%d: Hello, World!\n",i); i--; }while(i>0); printf("i = %d\n",i); ``` 選擇題題目 > 請選出下列程式碼的輸出結果 ```C #include <stdio.h> int main(){ int i = 8; int ans = 0; while(i>0){ switch(i%2){ case 0: ans += i; break; case 1: ans -= i; break; } i--; } printf("ans = %d\n",ans); } ``` * 選項A: 4 * 選項B: -3 * 選項C: 6 :::spoiler 參考解答 ```c i從8跑到1,遇到偶數ans要-i,遇到奇數則ans要+i。 ans = 8 - 7 + 6 - 5 ..... - 1 = 4 答案為: 選項A ``` ::: --- ### 陣列介紹 > 陣列是用於儲存很多相同型態的變數 #### 使用範例 `陣列`的宣告方式跟一般變數宣告很像,只是後面要多加`[]`並且裡面要放上代表`要儲存幾個數字`,陣列的`索引值`是從0開始 ```c int height[4] = {168,170,165,160}; //宣告height陣列裡面可以存放4個整數 索引值 0 1 2 3 記憶體位址 0x01 0x05 0x09 0x13 |-----|-----|-----|-----| | 168 | 170 | 165 | 160 | |-----|-----|-----|-----| printf("%d\n",height[0]); // 168 printf("%d\n",height[1]); // 170 printf("%p\n",height); // 0x01 printf("%p\n",&height[0]); // 0x01 printf("%p\n",(height+1)); // 0x05 printf("%p\n",&(height[1])); // 0x05 printf("%d\n",*(height+1)); // 170 ``` ```c int height[4]; int i; for(i = 0;i<4;i++){ scanf("%d",&height[i]); } for(i = 0;i<4;i++){ printf("%d : %d\n",i, height[i]); } ``` ```c int height[4] = {168,170,165,160}; int i, max_height; for(i = 0;i<4;i++){ if(i == 0){ max_height = height[0]; } else if(height[i]>max_height){ max_height = height[i]; } } printf("max_height = %d\n",max_height); ``` 如何改成找最小值呢? ## 2024/11/15 ### 今日目標 * 字元陣列、二維陣列 * 練習APCS題目 --- #### 二維陣列 ```c int height[3][3] = { {168,170,165}, {172,170,164}, {166,173,164} }; /* 0 1 2 |-----|-----|-----| 0 | 168 | 170 | 165 | |-----|-----|-----| 1 | 172 | 170 | 164 | |-----|-----|-----| 2 | 166 | 173 | 164 | |-----|-----|-----| */ printf("%d\n",height[1][0]); //172 printf("%d\n",height[0][2]); //165 printf("%d\n",height[2][1]); //173 ``` 讓使用者輸入數值到二維陣列 ```c #include <stdio.h> int main() { int arr[2][3]; int i, j; for(i = 0; i<2;i++){ for(j = 0;j<3;j++){ scanf("%d",&arr[i][j]); } } for(i = 0; i<2;i++){ for(j = 0;j<3;j++){ printf("%d ",arr[i][j]); } printf("\n"); } } ``` 選擇題題目 > 請選出下列程式碼的輸出結果 ```c #include <stdio.h> int main() { int arr[2][3] = { {1, 2, 3}, {4, 5, 6} }; int i, j, total = 0; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { if ((i + j) % 2 == 0) { total += arr[i][j]; } } } printf("total = %d\n", total); return 0; } ``` * 選項A : total = 9 * 選項B : total = 12 * 選項C : total = 15 * 選項D : total = 18 :::spoiler 參考解答 ```c 當(i+j)%2==0的時候 total 就要加上那個位置的值。 i => 0~1 j => 0~2 (i+j)%2==0的組合(i,j)有 => (0,0), (0,2),(1,1) 所以 arr[0][0] + arr[0][2] + arr[1][1] = 9 答案為: 選項A ::: #### 字元陣列 > 字元其實就是整數,字元陣列就是儲存一大堆的字(類似字串) [ASCII 維基百科](https://zh.wikipedia.org/zh-tw/ASCII) 字元對應數字 ```c char c = '5'; printf("字元'c' = %d\n",c); // 53 printf("%d\n",c - '0'); // 5 ``` 宣告字元陣列 > '\0' 這個字元是用來判斷字串是否結束,使用printf輸出字串要碰到 '\0' 才會停止 ```c char ca[] = {'a','b','c'}; char cb[] = "abc"; printf("ca[] = %s\n",ca); // abc,這樣輸出會有風險 printf("ca[]的大小 = %d\n",sizeof(ca)); // 3 /* ca陣列 索引值 0 1 2 |-----|-----|-----| | 'a' | 'b' | 'c' | |-----|-----|-----| */ printf("--------------\n"); printf("cb[] = %s\n",cb); // abc printf("cb[]的大小 = %d\n",sizeof(cb)); // 4 /* cb陣列 索引值 0 1 2 3 |-----|-----|-----|------| | 'a' | 'b' | 'c' | '\0' | |-----|-----|-----|------| */ ``` 利用scanf輸入字串 > Buffer Overflow ? ```c char cc[3]; printf("請輸入cc:"); scanf("%s",cc); // 會在最後補上 '\0',所以若輸入3個字元有可能會出問題 printf("%s\n",cc); int i; for(i = 0;cc[i]!='\0';i++){ printf("%c",cc[i]); } ``` --- ### APCS 實作題練習 [2017年3月第一題 - 秘密差](https://zerojudge.tw/ShowProblem?problemid=c290) ::: spoiler 參考解答 ```c #include <stdio.h> int main(){ char arr[1001]; int A = 0,B = 0,ans; scanf("%s",arr); int i; for(i = 0 ; arr[i]!='\0' ; i++){ if(i%2 == 0){ A += arr[i] - '0'; } else{ B += arr[i] - '0'; } } ans = A-B; if(ans<0){ ans = -ans; } printf("%d",ans); } ``` ::: [2021年11月第一題 - 修補圍籬](https://zerojudge.tw/ShowProblem?problemid=g595) :::spoiler 參考解答 ```c #include <stdio.h> int main(){ int n, h[101]; //輸入幾個圍籬 scanf("%d",&n); //輸入圍籬 int i; for(i = 0; i<n ;i++){ scanf("%d",&h[i]); } int need = 0; //總共需要的圍籬長度 for(i = 0;i<n;i++){ if(h[i]==0){ //如果圍籬被吹斷 if(i==0){ //如果是在第一個被吹斷 need = need + h[1]; } else if(i==n-1){ //如果是在最後一個被吹斷 need = need + h[n-2]; } else{ if(h[i-1]<=h[i+1]){ //如果左邊的圍籬小於等於右邊的 need = need + h[i-1]; } else{ need = need + h[i+1]; } } } } printf("%d",need); } ``` ::: [2020年10月第一題 - 人力分配](https://zerojudge.tw/ShowProblem?problemid=f312) ::: spoiler 參考解答 ```c #include<stdio.h> int main(){ int n, max_profit; int y_1, a_1, b_1, c_1, y_2, a_2, b_2, c_2; scanf("%d %d %d",&a_1,&b_1,&c_1); scanf("%d %d %d",&a_2,&b_2,&c_2); scanf("%d",&n); int i; for(i = 0;i<=n;i++){ y_1= i*i*a_1 + i*b_1 + c_1; y_2=(n-i)*(n-i)*a_2 + (n-i)*b_2 + c_2; if(i == 0){ //先用第一個當最大的 max_profit = y_1 + y_2; } else if(y_1+y_2>max_profit){ max_profit = y_1 + y_2; } } printf("%d",max_profit); } ``` ::: --- ## 2024/12/19 ### 今日目標 * 複習??? * 練習APCS題目 * 點飲料??? --- ### APCS 實作題練習 [2024年6月第一題 - 特技表演](https://zerojudge.tw/ShowProblem?problemid=o076) ::: spoiler 參考解答 (雙重迴圈,慢) ```c #include <stdio.h> int main(){ int n, h[1001]; scanf("%d",&n); int i; for(i = 0;i<n;i++){ scanf("%d",&h[i]); } int now_fly = 1; //到碰到比自己高的之前,總共飛了多少 int max_fly = 1; //所有飛的距離裡面哪一段飛最遠 for(i = 0;i<n;i++){ // 從第i棟大樓開始飛 int now_fly = 1; int j; for(j = i+1;j<n ;j++){ if(h[j-1]>h[j]){ now_fly += 1; } else{ break; } } if(now_fly>max_fly){ max_fly = now_fly; } } printf("%d\n",max_fly); } ``` ::: ::: spoiler 參考解答 (效率比較好) ```c #include <stdio.h> int main(){ int n, h[1001]; scanf("%d",&n); int i; for(i = 0;i<n;i++){ scanf("%d",&h[i]); } int now_fly = 1; //到碰到比自己高的之前,總共飛了多少 int max_fly = 1; //所有飛的距離裡面哪一段飛最遠 for(i = 1;i<n;i++){ if(h[i]<h[i-1]){ //如果目前高度比前一棟高度低的話 now_fly += 1; if(now_fly > max_fly){ max_fly = now_fly; } } else{ //如果碰到比自己高 now_fly = 1; } } printf("%d\n",max_fly); } ``` ::: ## 2025/01/03 ### 今日目標 * 喝飲料 * APCS(人力分配) * 下學期課程安排