# C++基礎語法介紹
## **程式語言是什麼?**
先看看維基百科怎麼說:
>程式語言(英語:programming language),是用來定義電腦程式的形式語言。它是一種被標準化的交流技巧,用來向電腦發出指令,一種能夠讓程式設計師準確地定義電腦所需要使用資料的電腦語言,並精確地定義在不同情況下所應當採取的行動。
簡單來說就是可以透過程式語言對電腦下達指令,讓電腦知道它要如何執行。而程式語言可大致分為以下三種:
* ### 機器語言
電腦是透過二進位(0、1)進行資料的儲存和計算,而機器語言就是以二進位的方式直接對電腦下達指令。這些指令是直接透過硬體結構讓電腦擁有這些功能,所以不同廠牌或種類所使用的機器語言都有所不同。
* ### 組合語言
以二進位的方式很難編寫,也不方便閱讀,於是就衍伸出以文字代替二進位來表達指令的組合語言。組合語言中每文字指令都對應到一個或多個機器語言指令,所以在執行指令前需要把它翻譯成機器語言,這個動作就稱為組譯。但由於組合語言依然對應到機器語言,所以仍然會有無法在不同處理器共通的問題。
* ### 高階語言
為了讓同一個程式可以在不同的處理器上運行,同時又能更貼近人類日常用語,讓程式更好理解,所以產生了高階語言。而高階語言翻譯成機器語言的方式主要有兩種:
1. 在程式執行前,透過編譯器一次翻譯所有程式碼。
2. 在程式執行時,一邊翻譯一邊執行。
<br>
## C++是什麼?
* ### C與C++
C語言是在1970年左右由Dennis Ritchie和Ken Thompson在貝爾實驗室開發出來的程式語言,它是由B語言演變而來,屬於編譯語言。C語言具有高階語言的特性,同時也有接近組合語言的速度。
C++ 也是在貝爾實驗室開發出來的,目的是打造一種具有物件導向的C語言,所以用C語言寫的程式大部份都可以在C++執行。
* ### C++的用途
C++ 是一個相當複雜的語言,它包含了C語言大部分的功能,使其能夠寫出具有底層硬體控制功能的程式,例如記憶體的安排;它也加入了物件導向等許多現今語言的特性,因此能夠處理更加貼近使用者的程式。作業系統如Windows、iOS以及瀏覽器如Chrome、Firefox等,和大家熟知的英雄聯盟,都是使用C++寫的。
* ### C++程式開發軟體
**1. Dev-C++**
Dev-C++ 是一款免費且非常容易使用的C++ 整合開發環境(IDE),不過它是一個比較古老的IDE,連編譯器也是好幾年前的,因此操作不是很方便。
( 但聽說最近有別的公司接手,詳情可參考此網站:https://github.com/Embarcadero/Dev-Cpp )
**2. Code::Blocks**
Code::Blocks是一個免費、針對C/C++設計的整合開發環境,操作簡單,但Code::Blocks本身不包含編譯器,需要另外安裝。
**3. Visual Studio**
Visual Studio是微軟的免費整合開發環境產品,有很好的除錯功能,但在使用的時候會消耗比較多的CPU和記憶體空間,環境設定也比較複雜。
**4. 軟體安裝參考網站**
Dev-C++:https://alwaysfreesir.blogspot.com/2017/05/devcpp-install.html
Code::Blocks:http://blog.ittraining.com.tw/2018/01/dev-c-codeblocks.html
Visual Studio:https://docs.microsoft.com/zh-tw/visualstudio/install/install-visual-studio?view=vs-2019
**5. 線上編譯器**
https://www.onlinegdb.com/
這是一個線上的程式編譯器,直接點進去就可以開始寫程式了,也可以把程式碼分享給其他人。
<br>
## **第一個程式**
```cpp=
#include <iostream>
using namespace std;
int main() {
cout << "Hello world!" << endl;
}
```
這是一個C++最初階的程式,它會在螢幕上印出「Hello World!」,看不懂沒關係,我們一行一行來解釋。
### #include<iostream>
#include就是引入一個函式庫,函式庫可以當作一個已經寫好的工具集。而iostream是一個輸入和輸出的函式庫。
### using namespace std;
using namespace是指引入一個命名空間,而std是標準函式庫的命名空間的名稱。如果沒有加上這一行,在使用函式庫中的函式就需要加上它的命名空間,例如`std::cout`。命名空間的作用是可以區分不同函式庫中相同名稱的函式。
### int main()
這是main函式,它是C++定義一個程式的起點,當執行一個程式時,就會從main函式開始,而大括號{ }內就是main函式的內容。如果看不懂也沒關係,對於初學者來說,目前只需要知道,要電腦執行的程式就要寫在這個大括號內。
### cout << "Hello world!" << endl;
cout是輸出的指令,後面的部分會再詳細介紹它的使用方法。這裡要特別注意的是,除了某些特定的情況,大部分的程式碼都要在行尾加上分號。
<br>
## 變數
變數是程式用來存放資料的空間,它會占有電腦的記憶體,在程式執行的過程中,可以對變數進行處理和運算。就像是數學方程式中的未知數X、Y一樣,代表著某一個資料。
### 宣告
在使用變數前,要先告訴電腦你要創造一個變數,這個動作叫做宣告。
* 宣告格式:`變數型別 變數名稱;`
例如`int x;`就是宣告一個整數變數x。
* 對宣告的變數做初始化:`變數型別 變數名稱 = 初始化的值;`
例:`int x = 0;`。
* 變數命名的規則:
1. 須以字母(a, b, c...)或下底線(_)為開頭
2. 不可以數字為開頭
3. 不可使用保留字(例:不可宣告一個為int的變數)
4. 字母一般使用小寫(非強制)
除上述規則外,變數名稱皆可自由命名。
### 常用變數型別
變數有很多種不同的型別,它可以用來存放各種不同類型的資料,以下是幾種常見變數型別:
#### **1. 整數**
整數型別用於儲存沒有小數點的數值。
##### int
* 範圍 -2^31^ ~ 2^31^-1 (-2147483648~2147483647)
* 佔用空間 4 Byte
```cpp
int x = -100;
```
##### unsigned int
* 範圍 0 ~ 2^32^ - 1
* 佔用空間 4 Byte
* 沒有負數
```cpp
unsigned int x = 0;
```
##### long long
* 範圍 -2^63^ ~ 2^63^-1
* 佔用空間 8 Byte
```cpp
long long x = 1000000000000000;
```
##### unsigned long long
* 範圍 0 ~ 2^64^-1
* 佔用空間 8 Byte
* 沒有負數
```cpp
unsigned long long x = 10;
```
#### **2. 浮點數**
浮點數是用來儲存有小數點的數值,但因為電腦二進位的儲存方式,導致浮點數可能會出現誤差,使用時要注意。
##### float
* 精準至約小數點後第七位
* 佔用空間 4 Byte
```cpp
float x = 3.1415;
```
##### double
* 精準至約小數點後第十五位
* 佔用空間 8 Byte
```cpp
double x = 3.1415926535;
```
#### **3.字元**
字元在電腦中有一個編號:ASCII碼,字元的儲存就是儲存它的編號。
##### char
* 以ASCII碼儲存一個字元
* 佔用空間 1 Byte
用`' '`表示一個字元
```cpp
char c = 'a';
```
##### string
* 儲存字串(多個字元)
用`" "`表示字串
```cpp
string s = "Hello world";
```
#### **4.布林(真假)值**
布林值是一個只會儲存true或false的型別:
##### bool
* 儲存 `true(1)` 或 `false(0)`
* 占用空間 1 Byte
```cpp=
bool x = true;
x = false;
x = 1;
x = 0;
```
<br>
## 輸入與輸出
C++的輸入和輸出是使用cin和cout來進行,在使用它們的時候需要引入「iostream」函式庫。
### cin
cin是C++用來輸入的物件,格式為`cin >> 變數;`,
如果要輸入多個值可以使用`cin >> 變數 >> 變數;`的格式。
```cpp=
int x, y;
cin >> x >> y;
```
### cout
cout是C++用來輸出的物件,格式為`cout << 要輸出的物件;`,可以輸出變數或是輸出一個值。
如果要輸出多個值可以使用`cout << 變數 << 變數;`的格式,在需要換行的地方可以輸出`endl`或是`'\n'`。
(`endl`和`'\n'`其實不太一樣,endl除了換行以外還會執行`cout.flush()`,會清空輸出緩衝區)
```cpp
cout << 100 << x << endl;
```
<br>
## 運算子
在C++中,可以使用運算子來對變數或數值做運算。以下介紹幾種常用的運算子,同時也會提到當兩種不同型別的變數進行運算時,電腦會如何判斷要使用哪個型別,以及如何做強制型別轉換。
1. ### **指定運算子**
使用等於`=`符號表示,會先對等號右邊進行運算,再將結果指定給左邊的變數。這個等號跟數學的等號不太一樣,需要花一點時間習慣。
```cpp=
int x;
x = 2 + 1; //x = 3 (//是註解,在C++程式編譯時不會被編譯)
x = x + 1; //x = 4,因為是先計算右邊的x + 1 = 3 + 1,再存到左邊的x
```
2. ### **算術運算子**
算術運算子就是數學的運算符號,具有跟數學四則運算一樣,先乘除後加減的規則。
* #### 加法 `+`
```cpp
int x = 3 + 2;
```
* #### 減法 `-`
```cpp
int x = 10 - 5;
```
* #### 遞增 `++`
遞增可分成前置`++x`和後置`x++`,它們的不同在於,前置的值會是運算之後的值,後置的值則是運算之前的值。可以看成前置`++x`是先加再用,而後置`x++`是先用再加。
```cpp=
int x = 0;
cout << ++x << endl; // x = 1, 輸出1
cout << x++ << endl; // x = 2, 輸出1
```
* #### 遞減 `--`
與遞增相同,一樣有分成前置和後置。
```cpp=
int x = 0;
cout << --x << endl; // x = -1, 輸出-1
cout << x-- << endl; // x = -2, 輸出-1
```
* #### 乘法 `*`
```cpp
int x = 2 + 3 * 4; //x = 14, 先乘除後加減
```
* #### 除法 `/`
兩個整數在做運算時, 當對兩個整數做除法`/`,會自行向下取整,也就是取商。
```cpp=
int x = 7 / 2; // x = 3
float y = 1.0 / 2.0; // y = 0.5
```
* #### 取餘數 `%`
```cpp
int x = 5 % 2; // x = 1
```
* #### 括號
在C++中,一樣可以使用括號來標示優先計算的部分,**且都是使用小括號`()`**。
```cpp=
cout << (1 + 2) * 3 << endl; //輸出9
cout << 2 * ((1 + 2) * 3 + 2) << endl; //輸出22
```
3. ### **比較運算子**
在比較運算中只會有 `true` 或 `false` 兩種結果。
* `<`小於、`>`大於
* `<=`小於等於、`>=`大於等於
* `==` 相等 、 `!=` 不相等
(相等是`==`,而`=`是指定運算子,意義跟用途都不同,要小心不要搞混。)
4. ### **邏輯運算子**
在邏輯運算中只會有 `true` 或 `false` 兩種結果。
* #### 邏輯AND `&&`
`A`、`B`皆為true時, `A && B` 為`true`,
否則 `A && B` 為 `false`。
| A && B | B = true | B = false|
| ------------ | -------- | -------- |
| **A = true** | true | false |
| **A = false**| false | false |
* #### 邏輯OR `||`
`A`、`B`皆為`false`時, `A || B` 為`false`,
否則 `A || B` 為 `true`。
| A \|\| B | B = true | B = false|
| ------------ | -------- | -------- |
| **A = true** | true | true |
| **A = false**| true | false |
* #### 邏輯NOT `!`
當 `A` 為 `true` 時,`!A` 為 `false`。
反之,`A` 為 `false` 時,`!A` 為 `true`。
| | A = true | A = false|
| -------- | -------- | -------- |
| **!A** | false | true |
### 型別轉換
型別轉換顧名思義就是把某個型別轉換成另一個型別。型別轉換主要有兩種,分別是**隱含型別轉換**及**強制型別轉換**。
* #### 隱含型別轉換
隱含型別轉換是C++ 會自動做的轉換,在一個運算式中,C++會選擇運算式中所有型別中儲存空間較大的型別,盡量避免失真的問題。
```cpp=
cout << 3 / 2 << endl; //輸出 1
cout << 3 / 2.0 << endl; //輸出 1.5
```
但如果是使用指定運算子`=`,C++就會以指定運算子左邊的資料型別為準。
```cpp=
int x = 3 / 2.0;
cout << x << endl; //輸出 1
```
#### 強制型別轉換
強制型別轉換是在程式運算過程中,對型別做強制的轉換。
轉換格式:
```
(轉換型別) 變數;
(轉換型別) 數值;
```
例如要將數字轉為字元的編號:
```cpp=
int x = 3;
cout << (double)x / 2 << endl; //輸出 1.5
cout << (char)97 << endl; //輸出「a」, 97是字元'a'在ASCII碼中的編號
```
<br>
## 選擇結構
選擇結構在C++ 中用於判斷條件並決定要執行哪些程式,C++使用`if`、`else`和`else if`作為選擇結構的語法,接下來會一個一個介紹它們的用法。
### if
`if`的使用格式如下:
```
if(判斷條件){
判斷條件成立時執行的程式;
}
```
`if`後的小括號用於放判斷式,如果判斷式運算結果為true,就會執行大括號內的程式碼。要注意大括號後不需要加分號。
以下是一個用於判斷你輸入的數是否大於100的程式,如果大於100,將輸出「x大於100」:
```cpp=
int x;
cin >> x;
if(x > 100){
cout << x << "大於100" << endl;
}
```
### else
若在**if**判斷為false,就可能會需要處理條件不成立的狀況,這時就會用到`else`。`else`需要接在`if`或`else if`後,`else if`會在後面提到。
以下是`else`的用法:
```
if(判斷條件){
判斷條件成立時執行的程式;
}else{
判斷條件不成立時執行的程式;
}
```
以下是一個用於判斷輸入的數是否大於100的程式。如果大於100,將輸出「x大於100」;否則輸出「x小於等於100」:
```cpp=
int x;
cin >> x;
if(x > 100){
cout << x << "大於100" << endl;
}else{
cout << x << "小於等於100" << endl;
}
```
### else if
當你需要多個選擇時,你可以使用`else if`來達成,`else if`可以接在`if`或`else if`後面,以下是`else if`的用法:
```
if(判斷條件1){
判斷條件1成立時執行的程式;
}else if(判斷條件2){
判斷條件2成立時執行的程式;
}
else{
判斷條件2不成立時執行的程式;
}
```
要特別注意的是,在整個選擇結構中,如果在其中一項成立,它就會跳過結構中後面的部分。
以下是一個用於判斷輸入的數是否大於100的程式。如果x大於100,將輸出「x大於100」;如果x等於100,則輸出「x等於100」;否則輸出「x小於100」:
```cpp=
int x;
cin >> x;
if(x > 100){
cout << x << "大於100" << endl;
}else if(x == 100){
cout << x << "等於100" << endl;
}else{
cout << x << "小於100" << endl;
}
```
<br>
## 迴圈
當你需要重複執行一樣的程式時,可以使用迴圈反覆執行相同的程式。在C++中,迴圈分為兩種:`for`迴圈和`while`迴圈。
### for
`for`迴圈通常用在需要重複的次數已知時使用,它的格式如下:
```
for(一開始要執行的動作; 迴圈執行條件; 每次迴圈跑完後要執行的動作){
迴圈內的程式;
}
```
在`for`迴圈的大括號後不需要加分號。
比較常見的程式寫法如下:
```cpp=
for(int i = 0; i < 執行次數; i++){
//迴圈的內容
}
```
以下是一個可以輸出0 ~ n - 1的程式:
```cpp=
int n;
cin >> n;
for(int i = 0; i < n; i++){
cout << i << ' ';
}
cout << endl;
```
### while
`while`迴圈的結構比`for`迴圈簡單,只需要一個迴圈執行條件,格式如下:
```
while(判斷條件){
迴圈內的程式;
}
```
這是一個計算輸入數字是幾位數的程式:
```cpp=
int x;
cin >> x;
int cnt = 0;
while(x > 0){
cnt++;
x = x / 10;
}
cout << cnt << endl;
```
`while`迴圈還有另一種寫法,是使用`do-while`。
```cpp=
do{
迴圈內容
}while(執行條件);
```
它跟`while`迴圈不同的地方是,`while`迴圈會在一開始就檢查是否執行迴圈,而`do-while`則是先執行過第一次之後再判斷是否繼續執行迴圈。還有要注意在`do-while`的大括號後需要加上分號,`while`迴圈則不用。
### break
`break`是迴圈的一個特別的指令,只能在迴圈內使用。當執行到`break`時,電腦會直接結束`break`所屬的迴圈。
以下是一個輸入數字n,輸出0 ~ n - 1的程式:
```cpp=
int n;
cin >> n;
int now = 0;
while(true){
if(now >= n)
break;
cout << now++ << ' ';
}
```
### continue
`continue`也是迴圈的指令,當執行到`continue`時他會跳過迴圈剩下的部分,直接回到判斷迴圈條件的步驟。
以下是一個輸入數字n,輸出0 ~ n - 1的偶數的程式:
```cpp=
int n;
cin >> n;
for(int i = 0; i < n; i++){
if(i % 2 == 1)
continue;
cout << i << '\n';
}
```
<br>
## 陣列
陣列是多個相同資料型別的變數所組成的,陣列中的每個元素都是一個變數。它的宣告格式如下:
```
變數型別 陣列名稱[陣列大小]; //陣列大小須為常數
```
當要使用時,用中括號[]加上索引值`陣列名稱[索引值]`來表示陣列的某個變數。要特別注意的是,**陣列的第一個位置索引值是`0`**,以下是一些簡單的操作方式:
```cpp=
int a[5];
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;
```
### 陣列和迴圈
陣列經常搭配迴圈一起使用,以下是一個簡單的程式:
```cpp=
int a[10];
for(int i = 0; i < 10; i++){
a[i] = 0;
}
```
這是一個把陣列索引`0~9`的值設為`0`的程式,可以看到這裡利用`for`迴圈的`i`作為陣列的索引。
<br>
## 結語
這份講義只有簡單介紹了C++ 的基礎語法,而C++ 還有很多有趣的東西值得你去探索,包括指標、類別、STL等,程式也還有很多不同的領域。
如果你對資訊奧林匹亞或是演算法有興趣的話,可以嘗試到一些線上解題網站寫個幾題,網路上也有很多學習的資源,講義最後也會附上幾個推薦網站。
但如果你想寫一些小遊戲的話,~~那你選錯語言了~~,你可能要學習物件導向程式設計,還有怎麼用程式繪製圖形等等。
最後,希望這份講義能幫助你學會C++的基礎使用方法,也期望你未來能夠在資訊這個領域持續學習、進步。
### **網路學習資源**
#### **AP325**
AP325是由++吳邦一++教授編寫,適合對程式基礎語法有一定了解的人,講義裡的例題也有放在TCIRC judge上。
https://drive.google.com/drive/folders/10hZCMHH0YgsfguVZCHU7EYiG8qJE5f-m
#### **臺大資訊之芽**
臺大資訊之芽是針對高中學生設計的培訓課程,以下是C語法班和算法班的講義,只要更改網址中年份的地方就可以找到歷年的講義。
* C語法班講義 https://tw-csie-sprout.github.io/c2021/#!slides.md
* 算法班講義 https://www.csie.ntu.edu.tw/~sprout/algo2021/
#### **建中校內培訓講義**
建中的校內培訓講義,從簡單的算法到各種困難的技巧都有。
https://tioj.ck.tp.edu.tw/articles/5
### **線上解題網站**
#### **TIOJ**
建中的線上解題系統。
https://tioj.ck.tp.edu.tw/
#### **zerojudge**
題目較多,但要找到適合的題目也相對較難。
https://zerojudge.tw/
#### **TCIRC judge**
台中一中的線上解題系統,裡面有AP325講義的題目。
https://judge.tcirc.tw/
#### **codeforces**
最多人參加的線上競賽網站,每隔幾天就會有一場線上比賽,並且大部份的比賽都有詳解。但因為是俄羅斯的網站,所以比賽的時間都是晚上10點左右,且都是英文。
https://codeforces.com/