陣列

前導:陣列是什麼?

變數可以幫助我們儲存資料,但如果今天有若干筆資料要輸入,我們勢必要宣告一堆變數。

int num1 , num2 , num3 ...... numn ;

這樣寫起來太麻煩也太累人了
於是程式設計師們開發了一個好用的工具,叫做「陣列Array」

如果 int、float、char...... 是宣告一個又一個的盒子
那麼 Array 就是宣告 N 個連貫的盒子

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

語法:如何宣告陣列?

在C++中,陣列的宣告被定義如下:

type arrayName[arraySize] ;
  • type 為型別
  • arrayName 為陣列名稱,與其它型別宣告時的命名規則相同
  • arraySize 為陣列長度,只能是非負整數或是非負整數變數

陣列的宣告

陣列的宣告範例如下:

int arr1[3] ;

float arr2[5] ;

double arr3[7] ;

char arr4[9] ;

陣列的索引值

int arr[1000] ;
cout << arr[100] << '\n' ;

範例宣告了一個名為 arr 的整數型別陣列,有 1000 個位置可以放整數
範例輸出 arr[100],而它的 100 便稱作陣列的索引值

陣列宣告時為陣列長度,而使用時為陣列索引值

有 1000 個位置那索引值可以放 1~1000 囉?
不,陣列永遠只能從 0 開始 (Re:從零開始的異世界生活)
這個情況的索引值範圍是 0~999

也就是 陣列長度為 N,其索引值的範圍為 [0]~[N-1]

語法:如何使用陣列

如何初始化

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

如果沒有初始化的後果

int arr[5] ;
cout << arr[2] << '\n' ;
//Output:48

未初始化的陣列,其值將會是亂數,不可用

陣列輸入和輸出

與其他型別變數操作相仿
不過可以指定單個陣列元素輸入和輸出

int arr[100] ;
cin >> arr[49] >> arr[50] ;
cout << arr[50] << '\n' ;

但太多筆數據時,使用陣列便顯得麻煩

int arr[100] ;
cin >> arr[0] >> arr[1] >> arr[2] >> ...... >> arr[99] ;
cout << arr[0] << arr[1] << arr[2] << ...... << arr[99] << '\n' ;

為了節省時間,陣列通常與迴圈搭配使用

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++中,陣列的宣告被定義如下:

type arrayName[arraySize1][arraySize2]...[arraySizeN];
  • type 為型別
  • arrayName 為陣列名稱,與其它型別宣告時的命名規則相同
  • arraySize 為陣列長度,只能是非負整數或是非負整數變數
    陣列之索引值皆為 0~N-1

多維陣列的宣告

以下以二維陣列作為範例

int arr1[3][4] ;

float arr2[5][6] ;

double arr3[7][8] ;

char arr4[9][10] ;
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 ;

動態宣告

int n ;
cin >> n ;
int arr[n] ;

語法錯誤但 IDE(整合開發環境) 會接受這種語法,使用上問題很大
尤其是區域記憶體溢出的問題,溢出時會使程式數值錯誤
所以務必用全域宣告陣列

int arr[50] ;

int main
{
    //讀取陣列
}

如果邊界範圍為 N
那麼 陣列的長度建議宣告為 N+5
這是為了 避免陣列溢位

補充:全域宣告的陣列預設值皆為 0

charstring

char

前導:char的陣列

char 就是字元型別,一個字元變數一次可以讀取一個字元
而如果要讀取一句話,或是很多字元的時候
就要用 char 宣告一個 array

語法:如何宣告char的陣列

char 的陣列宣告範例如下:

char ch[1000] ;

語法:如何初始化char陣列

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 宣告範例如下:

string str ;

語法:如何初始化string

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 的陣列宣告範例如下:

string str[5] ;

語法:如何初始化string陣列

string str1[3]={"Jack" , "Colten" , "Suifeng"};
//宣告有 3 個字串的陣列
//宣告時用 {} 括弧住初始化的內容與用 "" 夾著個別字串

string str2[5]=""
//str2 全為 '\0' (NULL)
//注意,這是特殊用法,只有 char 與 string 型別可以這麼做,其他型別不行
//僅可用 "" ,不可用''

語法:如何使用string陣列

使用字串陣列時,只需要在最後加上 [index] 即可存取字串中的元素

string str[3]={"Jack" , "Colten" , "Suifeng"} ;
cout << str[2] << '\n' ;
//Output:Suifeng
cout << str[2][2] << '\n' ;
//Output:i

#include <string>

C++自帶的用法與函數:

string str ;
getline(cin , str) ;
//得到一整行的輸入,包含空格,遇到換行時終止讀取

str.size() ;
//得到字串長度

str.length() ;
//得到字串長度

str[1] = 'C' ;
//存取字串的第 2 個元素,型別為字元

str.at(1) = 'C' ;
//存取字串的第 2 個元素,型別為字元
//會有超出邊界的警告

需導入 <string> 函式庫才可使用的函數:

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

邊界

在使用陣列時,如果遇到陣列長度為 lengtharr[i+N]
即便 i 的值有被嚴格限制在陣列範圍
加上常數 N 後卻很可能因此超出陣列範圍,也就是陣列的邊界
因此,要更改最大索引值為 length-N-1 以避免超出邊界

在邊界外賦值

int arr[50] ;
//邊界為arr[49]
arr[50] = 1000 ;
cout << arr[50] << '\n' ;

允許邊界外賦值延長陣列長度
但不可未延長陣列長度就進行操作,會有溢位問題

陣列不可為空arr[]

int arr[] ;
//ERROR

只有進行初始化時才可以不放陣列長度

int arr[]={1 , 2 , 3} ;

IO優化

陣列的輸入輸出動不動就是幾千幾萬筆的
在C++,這樣的輸入輸出會造成程式效率低下
於是我們使用 IO優化

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-的輸出入cin-cout和scanf-printf誰比較快?/