# C語言基礎教學文件 ## 前言 Hi,🥳🥳 感謝你參與活動,領取這份Hogan的C語言基礎禮包文件~ 📌 以下是Hogan C語言基礎禮包文件的內容 此份文件全為個人獨立製作完成,因此難免有疏漏 如有任何問題及發現紕漏,歡迎直接私訊我討論修改~ 最後更新時間:2022/7/28 此份文件為程式語言-C語言的基礎教學文件 如果喜歡此份文件,也歡迎在 Github & HackMD 按下喜歡以及收藏 所有的程式碼都會同步放置在 [Github](https://github.com/purmonth/Hogan.tech/tree/master/C-tutorial-1)上 以下內容除了C語言簡介部分以外 其他部分在不同程式語言間都是大同小異的 因此透過此份文件也可以略知**其他程式語言的基本語法** ### 看完這份文件能學到什麼 🔑 你將能學到: 🔺C語言在程式語言中的定位與功能 🔺C語言常見的型態和基本邏輯 🔺學習C或C以外程式語言者的基本語法 🔺從安裝程式編輯器開始教你手把手實作C語言 ### 誰適合閱讀這份文件呢? 🔑 適合: 🔺即將或是正在就讀程式語言相關科系者 🔺正在做未來科系抉擇的學生 🔺未來職涯發展想往軟、韌體發展者 🔺單純想了解什麼是寫程式以及什麼是程式語言者 🔺想要學習程式語言共同基本語法者 ### Hogan.tech的成立初衷 >希望每個正在這條路上探索的人, >都可以透過 Hogan.tech的教學嘗試進入程式領域。 ## 程式語言介紹 **程式語言**可以分成以下幾類 1. **機器語言 Machine Language**: 指機器才能懂的語言,通常是0、1所組成。 2. **組合語言 Assembly Language**: 接近機器語言的語言,比起純數字,開始**有一些簡單的符號**。 組合語言也必須經由Assembler來去做編譯,將組合語言轉換成機器語言 3. **高階語言 High Level Language**: 目前常見的C、C++、Java、JavaScript...等各式語言,都是此類型。包含一般常用的數學運算符號以及英文單字。必須經由Compiler來去做編譯,將高階語言轉換成更低階語言才能讓電腦去做執行。 C語言最早由Dennis Ritch,為了電腦上運行的Unix系統所設計出來的程式語言,第一次發展在1969年到1973年之間。 這邊也附上有趣的程式語言演進圖:https://hackmd.io/@greta/ByVDgXhsS 裡面也包含詳細的時間軸以及程式語言歷史。 ## C語言執行 通常大部分的書籍或是教學不會一開始就教執行,但是我自己是一個很喜歡動手做的人。先看到結果才去思考過程,因此將C語言執行放在這邊。 會教大家如何從下載編輯器開始撰寫自己第一支程式,並能夠執行顯示結果。 ### 線上編輯器 如果是第一次接觸程式,但是卻不知道從何下載起,並且執行程式呢? 下列的網站相當推薦讀者可以直接做執行。 https://www.programiz.com/c-programming/online-compiler/ 打開後可以發現C語言的程式碼,直接按下Run就能執行。 之後相關的程式碼也都可以複製、貼上於第七行之中,並且執行,都是可以看到結果的。 ```c= // 01 // Online C compiler to run C program online #include <stdio.h> int main() { // Write C code here printf("Hello world"); return 0; } ``` ### 下載編輯器 1. #### Window 如果讀者為Window作業系統使用者,那麼想要最簡單、快速執行程式的方式,推薦下載DevC++,透過下載並且開新檔案,一樣複製上述的程式碼,皆可以執行。 相關下載教學:https://www.youtube.com/watch?v=NTkwZsUasXU 相關教學影片:https://www.youtube.com/watch?v=5sc8ODdWTs8 2. ### Linux 如果讀者為Linux作業系統使用者,那麼相當推薦使用GCC並且透過終端機去執行。 相關教學影片:https://www.youtube.com/watch?v=oLjN6jAg-sY 3. ### Mac 如果讀者為Mac作業系統使用者,可以下載VScode套件去做編輯再透過GCC去做編譯。 相關教學影片:https://www.youtube.com/watch?v=YuutFT6Yhic ## 變數、資料型態、基本運算子 大部分高階程式語言,都會有變數以及資料型態的概念,以下也會介紹C語言常見的型態,也可以透過這些型態明白資料在電腦中是怎麼儲存的。 ### C語言資料型態 | 英文型態 | 資料型態 | 位元組 | | -------- | -------- | -------- | | char | 字元 | 1 | | int | 整數 | 2 | | float | 浮點數 | 4 | | double | 倍精度浮點數 | 8 | ### 變數 Variable 在C語言中,變數可以先做宣告,而命名規則如下: 1. 變數名稱只能包含英文字母、數字、底線。 2. 第一個字元只能為英文字母或是底線。 3. 變數名稱字數正常來說不限,但是有些編譯器在大於31個字元時,會有錯誤。 其中C語言為強型別語言,簡而言之,變數在做使用以及宣告以前,必須要給予型別。 例如:int x = 10; 即為宣告一個 x 變數,指定其為int(integer)整數型別,並指定此變數的值為10。 ### 常數 Constant 常數 (constant) 的值是固定的,如浮點數常數、字元常數、整數常數...等。 例如:const double pi=3.14; 以下是簡單的程式碼,由第四行可以知道,宣告了一個常數的浮點數型態稱為pi,並給予3.14的數值接下來透過第五行的指令將它印出來。 請讀者複製,並且執行看看 ```c= // 02 #include<stdio.h> int main(){ const double pi=3.14; printf("%f",pi); return 0; } ``` ### 基本運算子 基本運算子可以分成三類 1. 算數運算子 加( + )、減( - )、乘( * )、除( / )、取餘數( % ),與一般我們在操作計算機或是使用excel方式一樣。 3. 關係運算子: 大於( > )、小於( < )、等於( == )、不等於( != ),如同數學算式中,常見的關系運算符號。 4. 邏輯運算子 且AND( && )、或OR( || )、否NOT(!)三者皆為邏輯運算子。 邏輯運算子在電腦中扮演舉足輕重的角色,與不管是軟體、韌體、硬體有重大的關係,也是我們有時候會聽到的布林運算。 ## 輸入、輸出 ### 輸出 Output 輸出為一個程式語言最一開始學習的部分,通常也都會試著印出一串文字。 以下面的程式碼舉例,我們透過 printf 語法來印出一串字,這一串字由 " 符號所包起來,中間可以放入文字 Hello world。 ```c= // 03 #include <stdio.h> int main() { printf("Hello world"); return 0; } ``` 除了文字以外,也可以印出變數、空行、空格、浮點數...等等。 ```c= // 04 //標準的輸出語法 //printf("格式化字串",變數1,變數2,...); int x = 10; int y = 20; printf("%d %d",x,y); ``` ### 跳脫字元(Escape Sequence) 在格式化字串中,如果有特殊需要印出的東西,我們會使用跳脫字元,以下列舉幾個。 | 換行 | 跳格 | 雙引號 | 單引號 | 斜線 | 反斜線 | | -------- | -------- | -------- |-------- |-------- |-------- | | \ n | \ t | \ " | \ ' |\ / | \ \ | ```c= // 05 printf("Hello \nworld"); ``` 執行完後的結果,可以發現到,如果字串中間有跳脫字元,則會有此字元的功能。 以換行舉例,Hello 後面多了換行的跳脫字元,則印出的東西就會換行。 ```c= Hello world ``` ### 修飾子 讀者應該已經發現,如果要印出一個變數,都是在格式化字串中,先放入某種符號,後面再放置變數。 是的,而這種符號叫做修飾子。 以下也列舉幾個常用的修飾子,這些修飾子也會根據變數的型別,而有所不同。 | 十進位整數 | 字元 | 字串 | 浮點數 | 印出正負號 | 向左靠齊 | | -------- | -------- | -------- |-------- |-------- |-------- | | %d | %c | %s | %f | + | - | ```c= // 06 int a = 10; double b = 1.1; float c = 1.2; char d = 'd'; char e[] = "test"; //上面的字串本質上是一個陣列,也都會在下一次進階教學中,做詳細說明 ``` ### 輸入 Input 輸入也是相當重要的環節,程式通常是透過使用者的輸入,來去做各種輸出。 以下面的程式碼舉例,我們透過 scanf 語法讀入一個數字, 再透過 printf 印出一個數字。 ```c= // 07 #include <stdio.h> int main() { int number; scanf("%d",&number); printf("%d",number); return 0; } ``` ```c= // 08 //標準的輸入語法 //scanf("格式化字串",&變數1,&變數2,...); int x; scanf("%d",&x); printf("%d",x); ``` 我們可以發現到比起printf,scanf的語法中,變數前面多了一個符號 & 。 這個符號 & 稱為位址運算子。 透過這個符號來將使用者想要輸入的值,存入該變數的位址。 ## 選擇判斷 If...else... & Switch ### 1. if 判斷敘述 以下皆用程式碼來舉例,假如定義一個變數score,在某些條件下時會印出對應的文字。 並且用簡單的判斷式語法,來舉例。 讀者可以嘗試修改下面的score值,看會印出什麼? ```cpp= // 09 int score = 100; //1. if 敘述 if(score < 60){ printf("分數低於六十分"); } //2. if...else 敘述 if(score < 80){ printf("分數低於八十分"); }else{ printf("分數大於或等於八十分"); } //3. 巢狀 if 敘述 if(score > 80){ printf("分數大於八十分"); if(score == 100){ printf("分數等於一百分"); } } //4. if...else if...else 敘述 if(score < 80){ printf("分數低於八十分"); }else if(score < 90){ printf("分數大於八十分,但是小於九十分"); }else{ printf("分數大於九十分"); } ``` ### 2. switch 判斷敘述 switch 也是另一種判斷式的語法,通常在處理多種情況判斷時使用。 讀者可以試著執行以下的程式碼,也可以試著將break拿掉,看會發生什麼事。 ```cpp= // 10 switch(score){ case (60): printf("分數60分"); break; case (70): printf("分數70分"); break; case (80): printf("分數80分"); break; default: printf("其餘的分數"); break; } ``` 其中 break 用來跳脫 switch 區塊,而如果都沒有遇到的情況,則會進入 default 區域執行。 ## 迴圈 For Loop 迴圈大致上可以分成三種,主要功用在於,讓電腦可以重複執行你希望執行的敘述。 這邊嘗試使用三種不同的迴圈語法,印出十次的Hello World ### 1. for ```c= // 11 //for 語法 //for(初始值;判斷條件;設定遞增或遞減){ // 敘述; //} int i; for(i = 0;i < 10;i ++){ printf("Hello World\n"); } ``` ### 2. do…while ```c= // 12 //do ... while 語法 //設定初始值 //do{ // 敘述; // 設定遞增或遞減; //}while(判斷條件); int i = 0; do{ printf("Hello World\n"); i ++; }while(i < 10); ``` ### 3. while ```c= // 13 //while語法 //設定初始值 //while(判斷條件){ // 敘述; // 設定地增或遞減; //} int i = 0; while(i < 10){ printf("Hello World\n"); i++; } ``` 上面列了三種常見的迴圈語法,而我自己是比較習慣使用for迴圈的語法,也推薦讀者可以自己練習看看喔。 ### 無窮迴圈 我們有時候會聽到無窮迴圈,那麼無窮迴圈又是什麼呢? 只要一個迴圈中,永遠達不到自己設定的判斷條件,就會進入無窮迴圈,簡而言之,程式會一直執行,並且不會停下來。 透過以下為例,原本條件是當 i<10 時,就會執行迴圈一次。 這邊的i--是指說,每跑一次回圈,i就會減一,因此可以發現,i永遠都會小於10,進而一直執行。 ```c= // 14 for(i = 0;i < 10;i --){ printf("Hello World\n"); } ``` ## 函式 Function ### 函式的呼叫 1. 傳值呼叫:將變數的值,複製並傳給函式,不影響原來的變數值。 2. 傳參考呼叫:將變數的位址傳給函式,會影響原來的變數值。 以下快速用程式碼來看一下兩者的差異,不過這次還不會講解傳參考呼叫的原理。因為其中牽扯到了C語言最重要的一個概念指標(Pointer)。下一次C語言教學中,才會另外講解指標的概念。 有興趣研究 傳參考呼叫 的讀者,也歡迎參考以下資料 https://www.tutorialspoint.com/cprogramming/c_function_call_by_reference.htm #### 傳值呼叫 ```c= // 15 void swap(int a, int b) { b = a; printf("%d %d", a, b); } int main() { int a = 1; int b = 0; b = a; swap(a, b); printf("%d", a); // a = number 110 printf("%d", b); // b = number 120 return 0; } ``` #### 傳址呼叫(傳參考呼叫) ```c= // 16 void swap(int *a, int *b) { *b = *a; printf("%d %d", *a, *b); } int main() { int a = 1; int b = 0; b = a; swap(&a, &b); printf("%d", a); // a = number 110 printf("%d", b); // b = number 120 return 0; } ``` 目前也有讀者提出C99規格書中,未有 call by reference 一詞,不過也有原文書、中文書、國外知名教學網站亦有 call by reference 一詞。詳細都可以參考右方留言。 此份文件主要還是以教學為主,並且受眾為學習基礎C語言的人,所以這邊還是保留原文書一詞為主。 C99規格書: C99規格書為C語言標準,未有 call by reference 一詞,但有call by address,感謝讀者詳細查找資料。 原文書參考: A TEXTBOOK ON C: Fundamentals, Data Structures and Problem 第 7.12 章節 國外知名教學網站: https://www.tutorialspoint.com/cprogramming/c_function_call_by_reference.htm ### 遞迴函式 (Recursive Function) 遞迴函式最大的好處是可以讓人類更直覺地去閱讀程式碼。 1. 呼叫自己本身,停止條件則需要自己設定,千萬要注意,避免無限呼叫自己。 2. 相較於一般的回圈方式呼叫函數,容易造成記憶體不足 3. 可以改寫成迴圈形式 快速以費氏數列來舉例: ```c= // 17 #include <stdio.h> int f(int n){ if (n==1 || n==2){ return 1; }else{ return f(n-1)+f(n-2); } } int main() { //快速印出費氏數列第四個數字 printf("%d",f(4)); return 0; } ``` ### 內建函數-亂數 在每個程式語言中,除了自己實作一個函數以外,也可以使用內建的函數 用以下程式碼來給讀者參考,不過先不詳細說明,未來有機會會再出一份文件,詳細說明。 ```c= // 18 #include <stdlib.h> #include <time.h> srand((unsigned)time(NULL)); int main() { int a = 10; int b = 20; int num = a + rand() % b; return 0; } ``` * 數字 0~9 的亂數取法:rand() % 10 * 骰子點數 1~6 的亂數取法:1 + rand() % 6 * 整數 18~32 的亂數取法:18 + rand() % 15 * 五位數的亂數取法:10000 + rand() % 90000 ## 後記 以上所有的程式碼都會同步放置在 [Github](https://github.com/purmonth/Hogan.tech/tree/master/C-tutorial-1)上 所有的程式碼都是可以直接下載做使用的~ 如果喜歡此份文件,也希望大家可以在 Github 上幫我按下星星! HackMD 也可以幫忙按下愛心、收藏以及留言喔! 感謝大家的參與,未來也會再分享其他程式相關的懶人包或是文件!