# 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 也可以幫忙按下愛心、收藏以及留言喔!
感謝大家的參與,未來也會再分享其他程式相關的懶人包或是文件!