# 陣列
## 前導:陣列是什麼?
變數可以幫助我們儲存資料,但如果今天有若干筆資料要輸入,我們勢必要宣告一堆變數。
```cpp
int num1 , num2 , num3 ...... numn ;
```
這樣寫起來太麻煩也太累人了
於是程式設計師們開發了一個好用的工具,叫做「陣列Array」
如果 `int、float、char......` 是宣告一個又一個的盒子
那麼 Array 就是宣告 N 個連貫的盒子
![](https://i.imgur.com/baSAdxh.png)
## 語法:如何宣告陣列?
### 在C++中,陣列的宣告被定義如下:
```cpp
type arrayName[arraySize] ;
```
* `type` 為型別
* `arrayName` 為陣列名稱,與其它型別宣告時的命名規則相同
* `arraySize` 為陣列長度,只能是非負整數或是非負整數變數
### 陣列的宣告
陣列的宣告範例如下:
```cpp
int arr1[3] ;
float arr2[5] ;
double arr3[7] ;
char arr4[9] ;
```
### 陣列的索引值
```cpp
int arr[1000] ;
cout << arr[100] << '\n' ;
```
範例宣告了一個名為 `arr` 的整數型別陣列,有 1000 個位置可以放整數
範例輸出 `arr[100]`,而它的 100 便稱作陣列的索引值
**陣列宣告時為陣列長度,而使用時為陣列索引值**
有 1000 個位置那索引值可以放 1~1000 囉?
不,陣列永遠只能從 0 開始 (~~Re:從零開始的異世界生活~~)
這個情況的索引值範圍是 0~999
也就是 **陣列長度為 `N`,其索引值的範圍為 `[0]~[N-1]`**
## 語法:如何使用陣列
### 如何初始化
```cpp
int arr[3]={1 , 2 , 3} ;
//arr有3個元素,分別為1、2、3
int arr[]={1 , 2 , 3} ;
//arr的元素有1、2、3,程式會自動判斷陣列長度
int arr[3]={0} ;
//arr有 3 個元素,全部皆為 0
//注意,這是特殊用法,只有 0 可以這麼做,其他數值不行
//常用在建表
int arr[4] ;
arr[3] = 50 ;
//第4個元素 arr[3]=50
```
#### 如果沒有初始化的後果
```cpp
int arr[5] ;
cout << arr[2] << '\n' ;
//Output:48
```
**未初始化的陣列,其值將會是亂數,不可用**
### 陣列輸入和輸出
與其他型別變數操作相仿
不過可以指定單個陣列元素輸入和輸出
```cpp
int arr[100] ;
cin >> arr[49] >> arr[50] ;
cout << arr[50] << '\n' ;
```
但太多筆數據時,使用陣列便顯得麻煩
```cpp
int arr[100] ;
cin >> arr[0] >> arr[1] >> arr[2] >> ...... >> arr[99] ;
cout << arr[0] << arr[1] << arr[2] << ...... << arr[99] << '\n' ;
```
為了節省時間,陣列通常與迴圈搭配使用
```cpp
int n ;
cin >> n ; //陣列的長度
for (int i=0 ; i<n ; ++i) //輸入陣列
{
cin >> arr[i] ;
}
for (int i=0 ; i<n ; ++i) //初始化陣列
{
arr[i] = 0 ;
//與 int arr[n]={0} ; 等效
}
```
### 多維陣列
#### 在C++中,陣列的宣告被定義如下:
```cpp
type arrayName[arraySize1][arraySize2]...[arraySizeN];
```
* `type` 為型別
* `arrayName` 為陣列名稱,與其它型別宣告時的命名規則相同
* `arraySize` 為陣列長度,只能是非負整數或是非負整數變數
**陣列之索引值皆為 0~N-1**
### 多維陣列的宣告
>以下以二維陣列作為範例
```cpp
int arr1[3][4] ;
float arr2[5][6] ;
double arr3[7][8] ;
char arr4[9][10] ;
```
```cpp
int arr[3][4]={
{0, 1, 2, 3} , //初始化第 1 列
{4, 5, 6, 7} , //初始化第 2 列
{8, 9, 10, 11} //初始化第 3 列
};
int arr[][]={
{0, 1, 2, 3} , //初始化第 1 列
{4, 5, 6, 7} , //初始化第 2 列
{8, 9, 10, 11} //初始化第 3 列
};
int arr[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
//與上面兩個宣告方式等效
int arr[3][4]={0} ;
//arr有 3×4 個元素,全部皆為 0
//注意,這是特殊用法,只有 0 可以這麼做,其他數值不行
//常用在建表
int arr[3][4] ;
arr[2][3] = 50 ;
```
### 動態宣告
```cpp
int n ;
cin >> n ;
int arr[n] ;
```
語法錯誤但 IDE(整合開發環境) 會接受這種語法,使用上問題很大
尤其是區域記憶體溢出的問題,溢出時會使程式數值錯誤
**所以務必用全域宣告陣列**
```cpp
int arr[50] ;
int main
{
//讀取陣列
}
```
如果邊界範圍為 N
那麼 **陣列的長度建議宣告為 N+5**
這是為了 **避免陣列溢位**
補充:全域宣告的陣列預設值皆為 0
## `char` 與 `string`
### `char`
#### 前導:`char`的陣列
`char` 就是字元型別,一個字元變數一次可以讀取一個字元
而如果要讀取一句話,或是很多字元的時候
就要用 `char` 宣告一個 `array`
#### 語法:如何宣告`char`的陣列
`char` 的陣列宣告範例如下:
```cpp
char ch[1000] ;
```
#### 語法:如何初始化`char`陣列
```cpp
char ch[3]={'A' , 'B' , 'C'} ;
//ch有3個元素,分別為A、B、C
char ch[]={'A' , 'B' , 'C'} ;
//ch的元素有A、B、C,程式會自動判斷陣列長度
char ch[3]="" ;
//ch有 3 個元素,全部皆為 '\0' (NULL)
//注意,這是特殊用法,只有 char 與 string 型別可以這麼做,其他型別不行
//僅可用 "" ,不可用''
char ch[4] ;
ch[3] = 50 ;
//第4個元素 ch[3]='2'
//ASCII碼第 50 個是數字 2
char ch[4] ;
ch[3] = '5' ;
//第4個元素 ch[3]='5'
//單個字元的賦值請用 '' 或 "" 將字元框起來
char ch[4] ;
ch[3] = '5' + 1 ;
//ch[3] == '6'
//對字元進行操作,等同對 ASCII碼 的數值進行操作,'5'+1 後的 ASCII碼便是 '6'
char ch[10]={"Colten Orz"} ;
//ERROR
char ch[11]={"Colten Orz"} ;
//大於等於兩個字元請用 "" 將字串框起來
//"Colten Orz" 有 10 個字元
//C++ 會在字串最後放上 '\0' (NULL),因此這個字串共有 11 個字元,所以陣列大小要為(輸入字元數+1)
char ch[]={"Colten Orz"} ;
//ch的元素有{'C' , 'o' , 'l' , 't' , 'e' , 'n' , ' ' , 'O' , 'r' , 'z' , '\0'}
//程式會自動判斷陣列長度
char ch[]={'C' , 'o' , 'l' , 't' , 'e' , 'n' , ' ' , 'O' , 'r' , 'z'} ;
//不等價於 char ch[]={"Colten Orz"} ;
char ch[]={'C' , 'o' , 'l' , 't' , 'e' , 'n' , ' ' , 'O' , 'r' , 'z' , '\0'} ;
//等價於 char ch[]={"Colten Orz"} ;
```
### `string`
#### 前導:`string`的用意
不是每句話長度都相同,這樣在宣告上十分不易
於是有一個不需要考慮字元陣列長度的型別,稱作 `string`
`string` 就是字元陣列,但我們不用知道有多少個字元
#### 語法:如何宣告`string`
`string` 是一種型別
`string` 宣告範例如下:
```cpp
string str ;
```
#### 語法:如何初始化`string`
```cpp
string str1("caterpillar") ;
// 內容為指定的字串常量
string str2(str1) ;
// 以 str1 實例建立字串
string str3=str2 ;
//以 str2 實例建立字串
string str4 = "Justin" ;
// 內容為指定的字串常量
string str5(10, 'c') ;
//建立有 10 個 c 的字串
string str6="" ;
//str6 為 '\0' (NULL)
//注意,這是特殊用法,只有 char 與 string 型別可以這麼做,其他型別不行
//僅可用 "" ,不可用''
string str7(str2 , 6 , 3) ;
//從 str2 中的第 6 個位置開始複製 3 個字元
//str2="caterpillar" 從第 6 位 'p' 開始,複製 3 個字元 "pil" 初始化 str7
string str8 = str2 + "content" + str3 ;
//混合初始化
string str9 = str2.substr(3 , 9) ;
//從 str2 中的第 3 個位置開始複製 9 個字元
////str2="caterpillar" 從第 3 位 't' 開始,複製 9 個字元 "terpillar" 初始化 str9
string str10 = str2.substr() ;
//substr的()參數為空則複製整個 str2 至 str10
string str11(5 , 'A') ;
//複製 5 個字元 A 到 str11
string str12="Hello" + "World" ;
//ERROR
//用 + 串接字串時,前兩項須有其中一項為 string 型別變數
```
補充:string str ; 預設狀態下即為空字串(NULL)
#### 語法:如何宣告`string`陣列
`string` 的陣列宣告範例如下:
```cpp
string str[5] ;
```
#### 語法:如何初始化`string`陣列
```cpp
string str1[3]={"Jack" , "Colten" , "Suifeng"};
//宣告有 3 個字串的陣列
//宣告時用 {} 括弧住初始化的內容與用 "" 夾著個別字串
string str2[5]=""
//str2 全為 '\0' (NULL)
//注意,這是特殊用法,只有 char 與 string 型別可以這麼做,其他型別不行
//僅可用 "" ,不可用''
```
#### 語法:如何使用`string`陣列
使用字串陣列時,只需要在最後加上 `[index]` 即可存取字串中的元素
```cpp
string str[3]={"Jack" , "Colten" , "Suifeng"} ;
cout << str[2] << '\n' ;
//Output:Suifeng
cout << str[2][2] << '\n' ;
//Output:i
```
### #include <string>
C++自帶的用法與函數:
```cpp
string str ;
getline(cin , str) ;
//得到一整行的輸入,包含空格,遇到換行時終止讀取
str.size() ;
//得到字串長度
str.length() ;
//得到字串長度
str[1] = 'C' ;
//存取字串的第 2 個元素,型別為字元
str.at(1) = 'C' ;
//存取字串的第 2 個元素,型別為字元
//會有超出邊界的警告
```
需導入 <string> 函式庫才可使用的函數:
```cpp
string str ;
str.empty() ;
//如果字串為空則回傳True
str.clear() ;
//清空字串
str.insert() ;
//在字串中插入字串
string str="to be question";
string str2="the ";
string str3="or not to be";
str.insert(6,str2);
// to be the question
//在 str 第 6 個位置的下一個位置開始插入 str2
str.insert(6,str3,3,4);
// to be not the question
//在 str 第 6 個位置的下一個位置開始插入 str3 的部分元素
//從 str3 第 3 個位置的下一位開始數 4 個元素到 第 7 個位置
str.insert(10,"that is cool",8);
// to be not that is the question
//在 str 第 10 個位置的下一個位置開始插入 "that is cool" 的部分元素
//從 "that is cool" 的第 1 個位置開始數 8 個元素到第 8 個位置
str.insert(10,"to be ");
// to be not to be that is the question
//在 str 第 10 個位置的下一個位置開始插入 "to be "
str.insert(15,1,':');
// to be not to be: that is the question
//在 str 第 15 個位置的下一個位置開始插入 1 個 : 字元
str.insert (str.end(),3,'.');
// to be, not to be: that is the question...
//從 str 的最後插入 3 個 . 字元
```
## 技巧:陣列的應用與注意事項
### 建表
在輸入輸出時,題目都會要求輸出一組結果
像是輸入一個數字,要你判斷他是不是質數,因為只有一個數字,所以很簡單
但如果今天有好幾個數字要你判斷,那你勢必要對每個數字進行判斷
這也會造成程式的執行效率低下
倘若今天用建表的方式,只要執行一次就不用重複執行
而建表的概念就是實現輸入一組 `index` ,**只用 `arr[index]` 就能得到答案**
b004: 一個都不能少
http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b004
### 邊界
在使用陣列時,如果遇到陣列長度為 `length` 的 `arr[i+N]`
即便 `i` 的值有被嚴格限制在陣列範圍
加上常數 `N` 後卻很可能因此超出陣列範圍,也就是陣列的邊界
因此,**要更改最大索引值為 `length-N-1` 以避免超出邊界**
### 在邊界外賦值
```cpp
int arr[50] ;
//邊界為arr[49]
arr[50] = 1000 ;
cout << arr[50] << '\n' ;
```
**允許邊界外賦值延長陣列長度
但不可未延長陣列長度就進行操作,會有溢位問題**
### 陣列不可為空arr[]
```cpp
int arr[] ;
//ERROR
```
**只有進行初始化時才可以不放陣列長度**
```cpp
int arr[]={1 , 2 , 3} ;
```
### IO優化
陣列的輸入輸出動不動就是幾千幾萬筆的
在C++,這樣的輸入輸出會造成程式效率低下
於是我們使用 **IO優化** :
```cpp
ios::sync_with_stdio(0);
//解除 cin/cout 與 stdin/stdout(標準輸入輸出流) 的綁定
cin.tie(0);
//解除 cin 與 cout 的綁定
```
## 參考資料
新竹實驗中學C++程式語言教學講義
https://hackmd.io/@qR5cY2d3Ql2AdYtLfHFxVg/B18yT_i5Z?type=view
語言技術:C++ Gossip
https://openhome.cc/Gossip/CppGossip/index.html
【c++標準函式庫(STL)筆記】string介紹 (含常見功能: 數字、字串互轉,字串切割,找子字串)
https://ithelp.ithome.com.tw/articles/10231604?sc=rss.qu
C++陣列初始化為0
https://www.itread01.com/content/1546996331.html
如何使用陣列 (Array)
https://michaelchen.tech/c-programming/array/
Array declaration
https://en.cppreference.com/w/c/language/array
std::array<T,N>::operator[]
https://en.cppreference.com/w/cpp/container/array/operator_at
std::array
https://en.cppreference.com/w/cpp/container/array
C++教學
http://tw.gitbook.net/cplusplus/index.html
C++與演算法
https://www.csie.ntu.edu.tw/~b98902112/cpp_and_algo/index.html
C語言字元陣列的定義與初始化
https://www.itread01.com/content/1550203580.html
陣列宣告和賦值總結
https://www.itread01.com/content/1546701490.html
string 如何初始化为空?
https://bbs.csdn.net/topics/390692419
string初始化的几种方法
https://blog.csdn.net/allovexuwenqiang/article/details/4277555
C++ string(初始化和部分函数的使用)
https://blog.csdn.net/qq_34637408/article/details/71584616
string::insert
http://www.cplusplus.com/reference/string/string/insert/
C++的輸出入cin/cout和scanf/printf誰比較快?
https://chino.taipei/note-2016-0311C-%E7%9A%84%E8%BC%B8%E5%87%BA%E5%85%A5cin-cout%E5%92%8Cscanf-printf%E8%AA%B0%E6%AF%94%E8%BC%83%E5%BF%AB%EF%BC%9F/