--- title: CPP基礎.Lesson 4 description: 多維陣列,struct,qualifier,scope tags: 1th,講義,c++,語法 --- # CPP基礎.Lesson 4 ## 多維陣列 ### 什麼是維???! ![](https://i.imgur.com/4Xaw8vT.png =500x) | 維度 | 對應到... | | ---- | ------------- | | 零維 | int a | | 一維 | int a[10] | | 二維 | int a[10][10] | | ... | ... | ### 宣告多維陣列 ```cpp //型態 名稱 [大小][大小]... (初始化) int W[5][4]; //裡面裝垃圾值 int H[2][3] = {{1, 2, 3}, {4, 5}}; //H[1][2] == 0 int O[2][3] = {}; //全部裝零 //也可以不要寫最前面的大小(如果有初始化) int X[][2] = {{1, 2}, {3, 4}}; //最前面的大小是2 int I[][2] = {{1, 2}, {3}}; //同上,I[1][1] == 0 int x[][2][2] = {{{1, 2}, {3, 4}}, {{1, 2}, {3, 4}}} //最前面的大小會是2 int i[][2][2] = {{{1, 1}, {1}}, {{1}}} //最前面的大小也是2, 其他值為0 ``` ### 輸入陣列的值 (宜搭配for服用) ```cpp int winnie[10][20]; for(int i = 0; i < 10; i++) for(int j = 0; j < 20; j++) cin >> winnie[i][j]; ``` ![](https://i.imgur.com/IGxQo2R.jpg =400x) :::warning ### 注意! - 索引值從0開始 - 索引值只能是整數 - 也可以用變數當索引 - 讀到記憶體外就會RE吃到飽 ::: ### 陣列不能互相指定,比較 一維或多維都是 ```cpp int C[3][3] = {}; int o[3][3]; o = C; //compile error int V[3][3] = {}; if(C == V) // 不等於 cout << "impossible" << endl; ``` --- ## 修飾子 Qualifier ### 資料型態 - 變數的儲存方式 - 不同型態的變數所占大小不同 - bit? byte? 8 bits = 1 byte `Mbps` 和 `MB/s` 不一樣喔! ![](https://i.imgur.com/kObTIPn.png =286x) | 型別 | 意義 | | ------ | --------------- | | bool | boolean值(真值) | | char | 字元 | | int | 整數 | | float | 浮點數 | | double | 倍準浮點數 | ### 修飾什麼? #### 宣告額外性質 - 改變所占記憶體 - short、long、long long - 改變數值範圍 - unsigned、signed ```cpp int main(){ short int s; // 短整數 long int l; // 長整數 long long int ll; // 更長的整數 long double ld; // 長倍精度浮點(小)數 unsigned int u; // 無號(正)整數 } ``` :::info `<climits>, <limits>` 可以取得各型態範圍 ```cpp #include <climits> #include <limits> int main(){ //<climits> 的用法 int a = INT_MAX; //現在常見的電腦上是 2147483647 unsigned long b = ULONG_MAX; //<limits> 的用法 a = std::numeric_limits<int>::min(); //常見為 -2147483648 bool c = std::numeric_limits<double>::has_infinity; //true } ``` 空間大小: (sizeof(xxx) 回傳 xxx 所佔據的位元組數) C 與 C++ 標準皆沒有規範大小, 大多要看編譯時電腦的 CPU 架構與作業系統而定 ```cpp sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) ``` | 型別|32-bit Windows|64-bit Windows|64-bit MacOS/linux| |---|---|---|---| |short int|16 bits = 2 bytes|16 bits = 2 bytes|16 bits = 2 bytes| |int|32 bits = 4 bytes|32 bits = 4 bytes|32 bits = 4 bytes| |long int|32 bits = 4 bytes|32 bits = 4 bytes|64 bits = 8 bytes| |long long int|64 bits = 8 bytes|64 bits = 8 bytes|64 bits = 8 bytes| ::: #### const const: constant(不變的)的簡寫,有翻譯作常量 顧名思義,初始化後就不可再更改 必須在編譯時初始化 目的是要預防寫程式的人不小心寫錯 常用來修飾參數,可以預防函數使壞 ```cpp const double Pi = 3.1415926; double SurfaceArea(double r){ return Pi * r * r; } double Volume(double r){ return Pi * r * r * 3 / 4; } int main(){ Pi = 3.14; // CE: assignment of read-only variable 'Pi' double volume = Volume(1); } ``` #### static static: 靜態的 生命周期(下面會提到)不隨函數消長(整支程式永遠恰有一個) 可以想成:變數範圍不變、生命週期變為整個程式碼 ```cpp #include <iostream> int count(){ static int counter = 0; return counter++; } int main(){ for(int i=0; i<5; i++) std::cout << count() << " "; // 0 1 2 3 4 } ``` 另外,static 變數不能被其他 C++ 檔案使用 例如在標頭檔中宣告的 static 全域變數 在引入這個標頭檔的 cpp 檔中是無法使用(看不到)這個變數的 ```cpp // circles.cpp static double Pi = 3.14159; // 這行用了 static double SurfaceArea(double r){ return Pi * r * r; } ``` ```cpp // main.cpp double SurfaceArea(double r); int main(){ extern double Pi; // 如果沒有 static,這行可以拿到 Pi double P = 2 * Pi * 5; } //CE: undefined reference to `Pi' ``` #### 其他修飾子 - C++: extern, inline, volatile - C: register, restrict, \_Atomic... ### 總結 - short, long, unsigned 可以修飾資料型態 - const 可以避免意外修改 - static 可以讓變數一直活著 - 參考資料很雜,但放 [cppreference](https://zh.cppreference.com/w/cpp) 準沒錯 --- ## Struct 假設…你是個車輛經銷商 - 儲存車輛的資料 - 價格 - 年份 - 長、寬、高(體積) - 油耗量 - 最高時數 - …. #### solution 1 開好幾條陣列 ```cpp char carName[30][50]; int year[30]; int price[30]; float speed[30]; float oil[30]; ``` - 過於繁瑣 - 資料不好整理 #### solution 2 開一條二維陣列 ```cpp int Car[30][5]; //Car[n][0] for Car’s name //Car[n][1] for year //Car[n][2] for Price //Car[n][3] for speed //Car[n][4] for oil ``` - 不夠直觀,無法直接從Index中判斷資料類型 - 不能同時把不同類型的東西綁一起 #### 使用struct ```cpp struct Car{ char carName[50]; int year; int price; float speed; float oil; }; ``` - 簡單明瞭 - 存取方便 - 符合物件導向設計思維 ### 宣告 ```cpp struct name{ datatype data1; datatype data2; … }; ``` ```cpp struct Car{ char carName[50]; int year; int price; float speed; float oil; }; int main(){ Car Benz; cin >> Benz.carName >> Benz.year >> Benz.price >> Benz.speed >> Benz.oil; //用name.dataname來存取 Car Armed[20]; //也可以宣告struct 陣列 Armed[5] = Benz; //可用'='來賦予一個struct的所有值給另一個struct cout << "Name: " << Armed[5].carName << endl; cout << "Year: " << Armed[5].year << endl; cout << "Price: " << Armed[5].price << endl; cout << "Speed: " << Armed[5].speed << endl; cout << "Oil: " << Armed[5].oil << endl; } ``` :::info CONSTRUCTOR 建構子 方便初始化變數 ```cpp struct Car{ char carName[50]; int year; int price; float speed; float oil; Car(int _price){ price = _price; } }; Car Mazda(980000); ``` ::: --- ## Scope ### 變數的生命週期 變數**活著**的時候我們可以使用 **死後**無人知曉無影無蹤 ### Local Variables 活在<font color="#f00">block</font>裡的變數 在block裡宣告 (出生) 出block就死亡 ### Block block: 被大括號包起來的區域 <font color="#f39"></font> ```cpp { //This is a block } ``` ```cpp int foo(int n) { //連同函式主體一起組成的block } ``` ```cpp for (int i = 0; i < 5; i++) { //連同for一起組成的block } ``` ```cpp { { int a = 10; //a 出生 cout << a; //print a } cout << a; //編譯失敗 a 已經死掉 //error: 'a' was not declared in this scope } ``` ```cpp int main() { for (int i = 0; i < 5; i++) { //可以使用i } cout << i; //編譯失敗 i 已經死掉 //error: 'i' was not declared in this scope } ``` ### Global Variables 可以在程式的各個角落使用他 通常宣告在程式的頂部 在block, function 外 ```cpp #include <iostream> using namespace std; int global = 10; void func1() { global = global + 1; } void func2() { global = global + 2; } void func3() { global = global + 3; } void func4() { global = global + 4; } int main() { func1(); func2(); func3(); func4(); cout << global; } ``` 全域變數每個地方都可以改 :arrow_right: 出bug機率大 ### 如果區域變數的名稱跟全域變數相同 1. 編譯會過? 會 2. 那用誰的? 優先使用最後命名的 ```cpp #include<iostream> using namespace std; int x = 5; //global x int main() { int x = 2; //local x cout << x << endl; //print 2 } ``` ### namespace 如果今天你要和一堆人一起寫project 為了避免撞名,該怎麼辦? ```cpp int chen_max(int x, int y); int lee_max(int x, int y); int wang_max(int x, int y); ``` ```cpp #include <iostream> namespace chen{ int max(int x, int y){ return x > y ? x : y; }; } int main(){ //std 也是一個namespace std::cout << chen::max(3, 5); } ``` ### using namespace [namespace] 所有在[namespace]的名稱都可以使用 ```cpp #include <iostream> using namespace std; int main() { cout << "123"; } ``` ## 回家作業 [d626: 小畫家真好用](https://zerojudge.tw/ShowProblem?problemid=d626)