# 陣列 ## 前導:陣列是什麼? 變數可以幫助我們儲存資料,但如果今天有若干筆資料要輸入,我們勢必要宣告一堆變數。 ```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/