---
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)