# C++ 程式設計 ```cpp= #include<iostream> using namespace std; int main(){ //int i; for (int i=0;i<100;i++){ int j; } } ``` ## 標頭檔 寫程式前,要先引入函式庫,這樣才可以使用函式庫內的function ``` #include<函式庫名稱> ``` 像是要寫C++時,一定要引入`<iostream>`的函式庫 ``` #include<iostream> ``` ## 命名空間 命名空間又可以當作程式的識別碼,用來區分不同函式庫中相同名稱的function 以下程式碼為例,`cout`和`endl`前的`std`就式命名空間 ```cpp= #include<iostream> int main(){ std::cout<<"今天天氣真好"<<std::endl; } ``` 每次使用一次`cout`就要寫一次`std`,那這樣寫100次`cout`勢必很麻煩,因此可以直接全域定義程式碼會使用到`std`的命名空間 ```cpp= #include<iostream> using namespace std; int main(){ cout<<"今天天氣真好"<<endl; } ``` ## 註解 註解可以用來解釋程式碼,提高程式碼的可讀性,有 **單行註解** 或是 **多行註解** ,註解中的所有文字都會被編譯器忽略。 ### 單行註解 在`//`後的所有文字都會被當註解 ``` //註解文字 ``` ### 多行註解 在`/*`到`*/`之間的所有文字都會被當註解 ``` /* 註解文字 註解文字 註解文字 */ ``` ## 數據類型 ### 類型 C++常見的數據類型有6個 | 關鍵字 | 名稱 | |:------:|:------------:| | bool | 布林值 | | char | 字元 | | string | 字串 | | int | 整數 | | float | 浮點數 | | double | 雙精度浮點數 | | void | 無值 | ### 修飾符 數據類型又有一個或是多個類型修飾符可以使用: * singed 有號 * unsigned 無號 * short 短型 * long 長型 各類數據類型,占用大小,值的範圍參考下表 | 類型 | 修飾符+類型 | 占用大小(位元組) | 範圍 | |:------:|:------------------:|:----------------:|:----------------------------:| | bool | bool | 1 | 1是true 0是false | | char | char | 1 | -128 ~ 127 參考[ASCII碼](https://zh.wikipedia.org/wiki/ASCII) | | | signed char | 1 | -128 ~ 127 | | | unsigned char | 1 | 0 ~ 255 | | int | int | 4 | -2^31^ ~ 2^31^-1 | | | signed int | 4 | -2^31^ ~ 2^31^-1 | | | unsigned int | 4 | 0 ~ 2^32^ | | | short int | 2 | -32768 ~ 32767 | | | signed short int | 2 | 0 ~ 65535 | | | unsigned short int | 2 | -32768 ~ 32767 | | | long int | 4 | -2^31^ ~ 2^31^-1 | | | signed long int | 4 | -2^31^ ~ 2^31^-1 | | | unsigned long int | 4 | 0 ~ 2^32^ | | float | float | 4 | ±3.4×10^-38^ ~ ±3.4×10^38^ | | double | double | 8 | ±1.7×10^-308^ ~ ±1.7×10^308^ | ### string `string` 比較特別,他個概念就是多個字元組成的字串變數。 字元要使用單引號`''`,引號中間只能有一個字元 字串要用雙引號`""`,引號中間可以有多個字元 ## 變數 ### 定義 定義變數時,要先指定一個數據類型,再寫下變數名稱。 ``` 型態 名稱; ``` 舉例: ``` int a; float b; double c; string d; ``` 如果有多個同數據類型的變數,可以寫在同行用逗號隔開。 ``` int a,b,c; ``` ### 初始化 在定義變數時可以指定一個初始值讓變數初始化,初始化由一個等號和一個常量組成。 ``` 型態 名稱 = 初始值; ``` 舉例: ``` int a = 3, b = 4; float c = 0.6; char d = 'x'; string e = "test"; ``` 字元需用單引號`''`來表示 當變數沒有做初始化時,系統會自動初始化變數,參考下表: | 類型 | 初始化默認值 | |:------:|:------------:| | int | 0 | | char | '\0' | | string | "\0" | | float | 0 | | double | 0 | ### 常數 如果初始化定義的變數值不會更改時,可以使用`const`的修飾符,該變數值就無法有任何改變 ``` const 型態 名稱 = 初始值; const int a = 10; ``` ### 算數運算符 | 運算符 | 描述 | 範例 | |:------:|:----------------:|:-----:| | + | 兩數相加 | a + b | | - | 前數減後數 | a - b | | * | 兩數相乘 | a * b | | / | 前數除後數 | a / b | | % | 前數減後數的餘數 | a % b | | ++ | 整數值+1 | a++ | | -\- | 整數值-1 | a-\- | 實作: ```cpp= #include <iostream> using namespace std; int main(){ int a = 20; int b = 10; int c ; c = a + b; //可以自行更換運算符 cout << "c 的值是 " << c << endl ; } ``` ### 賦值運算符 | 運算符 | 描述 | 範例 | |:------:|:--------------------------------------:|:------------------------:| | = | 把右邊的值賦給左邊變數 | c = a + b | | += | 把左邊的值加上右邊值賦給左邊變數 | a += b (等同 a = a + b) | | -= | 把左邊的值減掉右邊值賦給左邊變數 | a -= b (等同 a = a - b) | | \*= | 把左邊的值乘上右邊值賦給左邊變數 | a \*= b (等同 a = a * b) | | /= | 把左邊的值除上右邊值賦給左邊變數 | a /= b (等同 a = a / b) | | %= | 把左邊的值除上右邊值的餘數賦給左邊變數 | a %= b(等同 a = a % b) | ## 變數作用域 ### 區域變數 變數只能在該區域才能使用,不同區域的變數可以有相同名稱。 ```cpp= #include<iostream> using namespace std; int main(){ int a=10,b=5; } void test(){ int a=5; } ``` 在`main`函式裡面的`a`和`test`函式裡面的`a`式兩個獨立的變數,互不影響。 `main`函式裡面的`b`不會在`main`函式以外的地方被讀到。 ### 全域變數 變數在整個程式裡面式共通的,任何區域的程式碼的可以去更改全域變數的值 ```cpp= #include<iostream> using namespace std; int a = 20; int main(){ int b=5; } void test(){ int c=5; } ``` 全域變數使用的名稱在區域變數宣告時就不能再次使用。 ## 輸入輸出 ### 標準輸出流cout `cout`要與流插入運算符`<<`,使用,方式如下 ```cpp= #include <iostream> using namespace std; int main( ) { char name[50] = "aura"; cout << name ; } ``` 不同的數據要一起輸出時要用`<<`隔開,方式如下 ```cpp= #include <iostream> using namespace std; int main( ) { char word[50] = "number = "; int num = 21; cout << word << num ; } ``` 變數也可以直接做運算 ```cpp= #include <iostream> using namespace std; int main( ) { int a = 21 , b = 13; cout << "a + b = " << a+b ; } ``` 換行可以用`endl`,等同`'\n'` ```cpp= #include <iostream> using namespace std; int main( ) { cout << "一二三" << endl << "四五六"; } ``` ### 標準輸出流cin `cout`要與流提取運算符`>>`,使用,方式如下 ```cpp= #include <iostream> using namespace std; int main( ) { int a; cin >> a; cout << "a = " << a << endl ; } ``` 可以進行多數據輸入,每個變數用`>>`隔開 ```cpp= #include <iostream> using namespace std; int main( ) { int a, b ; cin >> a >> b; cout << "a = " << a << endl ; cout << "b = " << b << endl ; } ``` ## 判斷 ### if 如果有符合條件,就會執行`if`內的程式碼 ``` if(條件式){ ... } ``` ### if...else 如果有符合條件,就會執行`if`內的程式碼,反之不符合的話,會執行`else`內的程式碼 ``` if(條件式){ ... } else{ ... } ``` ### 多if 如果有符合條件,就會執行`if`內的程式碼,如果不符合,會去檢查`else if`的條件,不符合就在往下檢查,直到`else`或是沒判斷式。 `else if` 可以是多個但第一個一定要是`if`。 ``` if(條件式){ ... } else if(條件式2){ ... } else{ ... } ``` ### switch ``` switch(變數名稱 或 運算式) { case 數字 或 字元: 程式碼1 break; case 數字 或 字元: 程式碼2 break; default: 程式碼3 break; } ``` switch後面括號可以直接放變數或是運算式 ``` switch(a){ ... } switch(x-y){ ... } ``` 當你的變數或是運算有符合`case` 後面的數值,就會進入該`case`執行程式碼 後面的`break`是用來跳出switch,不然會繼續找`case` ``` switch(a){ case 1: //當如果 a=1 就會執行這裡的程式碼 break; case 2: //當如果 a=2 就會執行這裡的程式碼 break; } ``` 如果你有多個條件要進入同一段程式碼,可以這樣寫 ``` switch(a){ case 1: case 3: //當如果 a=1 或 a=3 就會執行這裡的程式碼 break; case 2: //當如果 a=2 就會執行這裡的程式碼 break; default: //當如果 a不等於1或2 就會執行這裡的程式碼 break; } ``` `default`是當`case`都不成立時就會執行的段落,必須放在最後面 ``` switch(a){ case 1:case 3: //當如果 a=1 或 a=3 就會執行這裡的程式碼 break; case 2: //當如果 a=2 就會執行這裡的程式碼 break; } ``` ### 關係運算符 | 運算符 | 描述 | 範例 | |:------:|:--------------------:|:------:| | == | 兩數是否相等 | a == b | | != | 兩數是否不相等 | a != b | | > | 前數是否大於後數 | a > b | | < | 前數是否小於後數 | a < b | | >= | 前數是否大於等於後數 | a >= b | | <= | 前數是否小於等於後數 | a <= b | 回傳值為1(`true`)或是0(`false`) 舉例: ```cpp= #include <iostream> using namespace std; int main() { int a = 20; int b = 10; int c ; if( a == b ){ //括號內可自行更換運算符 cout << "a 等於 b" << endl ; } } ``` ### 邏輯運算符 | 運算符 | 描述 | 舉例 | 範例 | 程式碼 | |:------:|:------------:|:----------------:|:-------------------------:|:------------:| | && | 且運算符 | X條件 && Y條件 | a大於b 和 b大於c | a>b && b>c | | \|\| | 或運算符 | X條件 \|\| Y條件 | a小於b 或 a小於c | a<b \|\| a<c | | ! | 否(非)運算符 | !X條件 | 非a大於b(等同 a小於等於b) | ! a>b | ## 循環 ### for ``` for(起始式; 條件式; 更新式){ ... } ``` 起始式:進入迴圈第一次會執行的動作 條件式:每輪執行前,會做一次檢查,如果成立就繼續迴圈,直到條件式不成立 更新式:每當執行完一輪,就會執行一次更新式 實作: ```cpp= #include<iostream> using namespace std; int i; int main(){ for(i=1;i<=10;i++){ cout<<i<<endl; } } ``` > i會從一開始(i=1),如果小於等於10(i<=10),就會執行i+1(i++),直到i不小於等於10 ### while ``` while(條件式){ ... } ``` 進入迴圈前會先檢查條件,成立後才會進入迴圈,迴圈會一直執行條件式不成立為止 實作: ```cpp= #include<iostream> using namespace std; int i = 10; int main(){ while(i<10){ cout<<"有進入迴圈"<<endl; } } ``` > 在while迴圈裡,只要i一直小於10,那就會一直在迴圈裡面循環,直到i不小於10。 ### do...while ``` do{ ... }while(條件式) ``` 迴圈會先執行一次,才會檢查條件,之後會一直執行條件式不成立為止 實作: ```cpp= #include<iostream> using namespace std; int i = 10; int main(){ do{ cout<<"有進入迴圈"<<endl; }while(i<10) } ``` > 在while迴圈裡,只要i一直小於10,那就會一直在迴圈裡面循環,直到i不小於10。 ### break 在迴圈裡面執行到一半,要直接跳出迴圈時,可以使用`break`直接跳出,會跳離離他最近的迴圈 ```cpp= #include<iostream> using namespace std; int i = 1; int main(){ while(i<10){ cout<<i<<endl; if(i == 4){ break; } i++; } } ``` ## 函式 一般來說,除了有主函式`main()`以外,也可以自訂自己的函式,當如果有同一區段的程式會需要多次的重複執行,自訂函式就可以讓你的主函式美觀一點。 ### 宣告 ``` 回傳型態 名稱(引數){ 副程式程式碼 } Ex: void test1(){ 副程式程式碼 } ``` ### 回傳型態 一般用於回傳數值給呼叫的地方,如果沒有要回傳值可以用 void 。 常見型態: | 程式碼 | 名稱 | |:------:|:------------:| | void | 不會回傳東西 | | int | 回傳整數 | | char | 回傳字元 | | double | 回傳浮點數 | ### 名稱 副函式可以有多個,名稱可以自訂,但有些像是主程式的main名稱是不能用的, 如果遇到不行使用的名稱編譯器會跟你講,不用擔心 ### 參數&引數 引數可有可無,可以有多個引數,用於攜帶數值到副程式 在主程式的變數和副程式的變數名稱互不影響,即使取相同名稱也是不一樣的東西 呼叫函式時,提供給函式的資料叫做引數(argument),接受引數的叫做參數(parameter) ```cpp= #include<stdio.h> #include<stdlib.h> //一個引數 void test1(int a){ //副程式程式碼 } //多個引數 void test2(int a,char b,int c){ //副程式程式碼 } //沒引數 void test3(){ //副程式程式碼 } int main(){ int k=10,v=30; char c='a'; test1(k); test2(k,a,v); test3(); } ``` <font color=#FF0000>注意,副函式宣告需要在main函式之前</font> 程式執行只會先從main函式執行,當有呼叫到副函式才會跳到副函式。 ### 回傳值 回傳數值要用`return`,但要回傳的值資料型態要跟宣告副函式時的資料回傳型態一樣, 只要執行到`return`就會直接跳回到呼叫副程式的地方 參考以下程式碼。 ```cpp= #include<stdio.h> #include<stdlib.h> int add(int x,int y){ int z=x+y; return z; } int main(){ int a=10,b=30,d; d=add(a,b); //執行後d會等於40 } ``` ## 數字 要使用這些數學函式時,需要引用數學頭文件 ``` #include <cmath> ``` 常用的數學函式: | 函數 | 回傳值型態 | 描述 | |:------------------:|:----------:|:------------------------------------:| | sin(double) | double | 正弦 | | cos(double) | double | 餘弦 | | tan(double) | double | 正切 | | log(double) | double | 自然對數 | | pow(double,double) | double | 前數為x,後數為y,函數會回傳x的y次方 | | sqrt(double) | double | 平方根 | | round(double) | int | 將小數四捨五入成整數 | | abs(int) | int | 絕對值 | | fabs(double) | double | 絕對值 | ### 隨機數 要使用這些隨機函數時,需要引用時間頭文件,這樣隨機函數才會隨著時間有變化,不然`rand()` 結果會固定。 ```cpp= #include <iostream> #include <ctime> using namespace std; int main () { int i,j; // 設定種子 srand( (unsigned)time( NULL ) ); // 執行10次 for( i = 0; i < 10; i++ ){ j= rand();// 產生隨機數字 cout << j << endl; } return 0; } ``` ## 陣列 C++支援陣列數據結構,可以存放固定大小相同類型的集合。 ### 宣告 宣告一個陣列,需要指定元素類型、數量 ``` 變數型態 陣列名稱 [ 陣列大小 ] ``` Ex.宣告一個類型為int,元素數量為5,名稱為a的陣列 ``` int a[5]; ``` 陣列有 n 個空間,那編號就是是 0 ~ n - 1 | 編號 | a[0] | a[1] | a[2] | a[3] | a[4] | |:----:|:----:|:----:|:----:|:----:|:----:| | 數值 | 0 | 0 | 0 | 0 | 0 | ### 初始化 在C++中,可以逐個初始化陣列內的元素 `{}`大括號內的元素數量,不能超過`[]`中括號內的數字 ``` int a[5] = { 2 , 1 , 4 , 5 , 3 }; ``` | 編號 | a[0] | a[1] | a[2] | a[3] | a[4] | |:----:|:----:|:----:|:----:|:----:|:----:| | 數值 | 2 | 1 | 4 | 5 | 3 | 如果確定陣列內的元素數量和值,可以直接宣告,此時`[]`中可以不用打數字 ``` int a[] = { 2 , 1 , 6 , 8 , 4 , 3 }; ``` | 編號 | a[0] | a[1] | a[2] | a[3] | a[4] | a[5] | |:----:|:----:|:----:|:----:|:----:|:----:|:----:| | 數值 | 2 | 1 | 6 | 8 | 4 | 3 | ### 數值修改 有一個陣列如下: ``` int a[] = {1,2,3}; ``` | 編號 | a[0] | a[1] | a[2] | |:----:|:----:|:----:|:----:| | 數值 | 1 | 2 | 3 | 修改數字 ``` a[1]=7; ``` | 編號 | a[0] | a[1] | a[2] | |:----:|:----:|:----------------------------:|:----:| | 數值 | 1 | <font color=#FF0000>7</font> | 3 | ## 字串 C++有兩種字串的表示法 * 字元陣列 * string 類型 ### 字元陣列 字元字串是一些字元和結尾為`\0(又稱為null)`結尾組成的陣列 ### * 定義 宣告一個類型為char(字元),元素數量為6,名稱為word的陣列 ``` char word[6] = { 'H', 'e', 'l', 'l', 'o', '\0' }; ``` 同樣的也可以寫成這樣: ``` char word[] = "Hello"; ``` C++編譯器在初始化字元陣列時,會自動把`'\0'`放在尾端 | 編號 | word[0] | word[1] | word[2] | word[3] | word[4] | word[5] | |:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:| | 數值 | 'H' | 'e' | 'l' | 'l' | 'o' | '\0' | 範例: ```cpp= #include <iostream> using namespace std; int main () { char word1[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; char word2[] = "Hello"; cout << word1 << endl; cout << word2 << endl; return 0; } ``` 這兩種執行結果會一樣 有一些函式可以用來控制字串 | 函式 | 說明 | |:----:|:----:| | strcpy(s1, s2); | 複製字串2(s2)到字串1(s1) | | strcat(s1, s2); | 把字串2(s2)連接到字串1(s1)的尾端 | | strlen(s1); | 回傳字串1(s1)的長度 | | strchr(s1, c); | 回傳字元c在字串1(s1)第一次出現的位置 | | strstr(s1, s2); | 回傳字串2(s2)在字串1(s1)第一次出現的位置 | ### string 類型 string除了有上述字元陣列的功能,引入`<string>`的頭文件,還有增加其他更多個功能可以使用。 ```cpp= #include <iostream> #include <string> using namespace std; int main () { string str1 = "Hello"; string str2 = "World"; string str3; int len ; // 複製str1到str3 str3 = str1; cout << "str3 : " << str3 << endl; // 連接str1和str2 str3 = str1 + str2; cout << "str1 + str2 : " << str3 << endl; // str3的字串長度 len = str3.size(); cout << "str3.size() : " << len << endl; return 0; } ``` ## 指標 ### 指標是什麼? 平常程式執行時 ``` int main(){ int a = 18; int b = 7; int c = 50; int d = 100; int e = 12; } ``` 以 `int a = 18;` 為例,程式執行時,處理器會去跟記憶體要一塊空間,把18這個資料放進去。 | 變數型態 | 位元組 | |:--------:|:------:| | bool | 1 | | char | 1 | | int | 4 | | long | 8 | | float | 4 | | double | 8 | 一塊空間的大小,會隨著資料型態產生變化,把記憶體比喻成一棟大樓,一個位元組為一層樓,像是一個`int`變數就需要4層樓才能存放。 以上述程式碼舉例,存放在記憶體內就長這樣 | 記憶體位址(起始位址) | 數值 | |:----------:|:-----------:| | 0x0012FF6c | ... | | 0x0012FF70 | 18 | | 0x0012FF74 | 7 | | 0x0012FF78 | 50 | | 0x0012FF7c | 100 | | 0x0012FF80 | 12 | | 0x0012FF84 | ... | 註1:記憶體位址是由處理器分配的,每次執行程式時記憶體位址都可能不一樣。 註2:記憶體位址為16進位。 <br><br> 也就是說,當我們宣告一個變數時,會有三個元素: | 變數位址(起始位址) | 變數數值 | 變數名稱 | |:----------:|:-----------:| :---: | | 0x0012FF70 | 18 | a | 除禮器會向記憶體要一塊空間來儲存變數,這個儲存空間有一個起始位址。加上這個變數的名稱a與變數值18。 通常會把變數的位址,稱為「指向該變數的指標」。 ### 取址 在`C++`中取址的方式就是放`&`在變數前面 ```cpp= #include<iostream> using namespace std; int main(){ int a = 18; cout << "變數 a 的值:" << a << endl; cout << "變數 a 的記憶體位址:" << &a << endl; } ``` 這個程式中,宣告了一個 int 整數 a,並印出「&a」的值,知道 a 所在的記憶體位址 ### 取值 利用`*pointer`的方式去讀取該位址的值 ```cpp= #include<iostream> using namespace std; int main(){ int a = 18; cout << "變數 a 的值:" << a << endl; cout << "變數 a 的記憶體位址:" << &a << endl; cout << "變數 a 的位址的值:" << *&a << endl; } ``` 也可以說,`*&a`和`a`是等價的。 ### 指標變數 當今天有了指標,就會需要存放指標的變數 平常程式執行時 ``` int* pointer ``` 宣告時,用`*`來表示 pointer 這個變數是個指標 ``` int b; b = 2; int* pointer; pointer = &b; ``` `&`是用來把變數的地址取出來, <font color=#FF0000>注意,不能寫成`pointer = b;`, pointer 是專門存放地址的變數。</font> ``` pointer = &b; ``` 又稱:指標變數 pointer 指向了變數 b 當要取指標變數的值時,也等同於取變數b的值 ```cpp= #include<iostream> using namespace std; int main(){ int b = 18; int* pointer = &b cout << "變數 b 的值:" << b << endl; cout << "變數 b 的記憶體位址:" << &b << endl; cout << "變數 pointer 的值:" << pointer << endl; cout << "取 pointer 位址的值:" << *pointer << endl; } ``` ## 數據結構 ###### tags: `C/C++` ## 存儲