## 3.1 數組 (Arrays)
數組(Arrays) 是在內存中連續存儲的一組同種數據類型的元素(變量),每一數組有一個唯一名稱,通過在名稱后面加索引(index)的方式可以引用它的每一個元素。
也就是說,例如我們有5個整型數值需要存儲,但我們不需要定義5個不同的變量名稱,而是用一個數組(array)來存儲這5個不同的數值。注意數組中的元素必須是同一數據類型的,在這個例子中為整型(int)。
例如一個存儲5個整數叫做billy的數組可以用下圖來表示:

這里每一個空白框代表數組的一個元素,在這個例子中為一個整數值。白框上面的數字0 到4 代表元素的索引(index)。注意無論數組的長度如何,它的第一個元素的索引總是從0開始的。
同其它的變量一樣, 數組必須先被聲明然后才能被使用。一種典型的數組聲明顯示如下:
`type name [elements];`
這里type 是可以使任何一種有效的對象數據類型(object type),如 int, float...等,name 是一個有效地變量標識(identifier),而由中括號[]引起來的elements 域指明數組的大小,即可以存儲多少個元素。
因此,要定義上面圖中顯示的 billy 數組,用一下語句就可以了:
`int billy [5];`
備注:在定義一個數組的時候,中括號[]中的elements 域必須是一個常量數值,因為數組是內存中一塊有固定大小的靜態空間,編譯器必須在編譯所有相關指令之前先能夠確定要給該數組分配多少內存空間。
### 初始化數組(Initializing arrays)
當聲明一個本地范圍內(在一個函數內)的數組時,除非我們特別指定,否則數組將不會被初始化,因此它的內容在我們將數值存儲進去之前是不定的。
如果我們聲明一個全局數組(在所有函數之外),則它的內容將被初始化為所有元素均為0。因此 ,如果全局范圍內我們聲明:
`int billy [5];`
那么billy 中的每一個元素將會被初始化為0:

另外,我們還可以在聲明一個變量的同時把初始值付給數組中的每一個元素,這個賦值用花括號{ }來完成。例如:
`int billy [5] = { 16, 2, 77, 40, 12071 };`
這個聲明將生成如下數組:

花括號中我們要初始化的元素數值個數必須和數組聲明時方括號[ ]中指定的數組長度相符。例如,在上面例子中數組billy 聲明中的長度為5,因此在后面花括號中的初始值也有5個,每個元素一個數值。
因為這是一種信息的重復,因此C++允許在這種情況下數組[ ]中為空白,而數組的長度將有后面花括號{}中數值的個數來決定,如下例所示。
`int billy [] = { 16, 2, 77, 40, 12071 };`
### 存取數組中數值(Access to the values of an Array)
在程序中我們可以讀取和修改數組任一元素的數值,就像操作其他普通變量一樣。格式如下:
`name[index]`
繼續上面的例子,數組billy 有5個元素,其中每一元素都是整型int,我們引用其中每一個元素的名字分別為如下所示:

例如,要把數值75存入數組billy 中第3個元素的語句可以是:
`billy[2] = 75;`
又例如,要把數組billy 中第3個元素的值賦給變量a,我們可以這樣寫:
`a = billy[2];`
因此,在所有使用中,表達式billy[2]就像任何其他整型變量一樣。
**注意**數組billy 的第3個元素為billy[2],因為索引(index)從0開始,第1個元素是billy[0],第2個元素是billy[1],因此第3個是 billy[2]。同樣的原因,最后一個元素是billy[4]。如果我們寫billy[5],那么是在使用billy的第6個元素,因此會超出數組的長度。
在C++ 中對數組使用超出范圍的index是合法的,這就會產生問題,因為它不會產生編譯錯誤而不易被察覺,但是在運行時會產生意想不到的結果,甚至導致嚴重運行錯誤。超出范圍的index 之所以合法的原因我們在后面學習指針(pointer)的時候會了解。
學到這里,我們必須能夠清楚的了解方括號[ ]在對數組操作中的兩種不同用法。它們完成兩種任務:一種是在聲明數組的時候定義數組的長度;另一種是在引用具體的數組元素的時候指明一個索引號(index)。我們要注意不要把這兩種用法混淆。
int billy[5]; // 聲明新數組(以數據類型名稱開頭)
billy[2] = 75; // 存儲數組的一個元素
其它合法的數組操作:
~~~
billy[0] = a; // a為一個整型變量
billy[a] = 75;
b = billy [a+2];
billy[billy[a]] = billy[2] + 5;
| // arrays example
#include
int billy [ ] = {16, 2, 77, 40, 12071};
int n, result=0;
int main () {
for ( n=0 ; n<5 ; n++ ) {
result += billy[n];
}
cout << result;
return 0;
} | 12206 |
~~~
### 多維數組(Multidimensional Arrays)
多維數組(Multidimensional Arrays)可以被描述為數組的數組。例如,一個2維數組(bidimensional array)可以被想象成一個有同一數據類型的2維表格。

jimmy 顯示了一個整型(int )的3x5二維數組,聲明這一數組的的方式是:
`int jimmy [3][5];`
而引用這一數組中第2列第4排元素的表達式為:**jimmy[1][3]**

(記住數組的索引總是從0開始)。
多維數組(Multidimensional arrays)并不局限于2維。如果需要,它可以有任意多維,雖然需要3維以上的時候并不多。但是考慮一下一個有很多維的數組所需要的內存空間,例如:
`char century [100][365][24][60][60];`
給一個世紀中的每一秒賦一個字符(char),那么就是多于30億的字符!如果我們定義這樣一個數組,需要消耗3000M的內存。
多維數組只是一個抽象的概念,因為我們只需要把各個索引的乘積放入一個簡單的數組中就可以獲得同樣的結果。例如:
`**int jimmy [3][5];** 效果上等價于
**int jimmy [15];** (3 * 5 = 15)`
唯一的區別是編譯器幫我們記住每一個想象中的維度的深度。下面的例子中我們就可以看到,兩段代碼一個使用2維數組,另一個使用簡單數組,都獲得同樣的結果,即都在內存中開辟了一塊叫做jimmy的空間,這個空間有15個連續地址位置,程序結束后都在相同的位置上存儲了相同的數值,如后面圖中所示:
~~~
| // multidimensional array
#include
#define WIDTH 5
#define HEIGHT 3
int jimmy [HEIGHT][WIDTH];
int n,m;
int main (){
for (n=0; n<HEIGHT; n++) {
for (m=0; m
jimmy[n][m]=(n+1)*(m+1);
}
return 0;
} | // pseudo-multidimensional array
#include
#define WIDTH 5
#define HEIGHT 3
int jimmy [HEIGHT * WIDTH];
int n,m;
int main (){
for (n=0; n<HEIGHT; n++){
for (m=0; m
jimmy[n * WIDTH + m]=(n+1)*(m+1);
}
return 0;
} |
~~~
上面兩段代碼并不向屏幕輸出,但都向內存中的叫做jimmy的內存塊存入如下數值:

我們用了宏定義常量(#define)來簡化未來可能出現的程序修改,例如,如果我們決定將數組的縱向由3擴大到4,只需要將代碼行:
`#define HEIGHT 3`
修改為 :
`#define HEIGHT 4`
而不需要對程序的其他部分作任何修改。
### 數組參數(Arrays as parameters)
有時候我們需要將數組作為參數傳給函數。在C++ 中將一整塊內存中的數值作為參數完整的傳遞給一個函數是不可能的,即使是一個規整的數組也不可能,但是允許傳遞它的地址。它們的實際作用是一樣的,但傳遞地址更快速有效。
要定義數組為參數,我們只需要在聲明函數的時候指明參數數組的基本數據類型,一個標識后面再跟一對空括號[]就可以了。例如以下的函數:
`void procedure (int arg[])`
接受一個叫做arg的整型數組為參數。為了給這個函數傳遞一個按如下定義的數組:
`int myarray [40];`
其調用方式可寫為:
`procedure (myarray);`
下面我們來看一個完整的例子:
~~~
| // arrays as parameters
#include
void printarray (int arg[ ], int length) {
for (int n=0; n<length; n++) {
cout << arg[n] << " ";
}
cout << "\n";
}
int main () {
int firstarray[ ] = {5, 10, 15};
int secondarray[ ] = {2, 4, 6, 8, 10};
printarray (firstarray,3);
printarray (secondarray,5);
return 0;
} | 5 10 15
2 4 6 8 10 |
~~~
可以看到,函數的第一個參數(int arg[ ])接受任何整型數組為參數,不管其長度如何。因此,我們用了第2個參數來告知函數我們傳給它的第一個參數數組的長度。這樣函數中打印數組內容的for 循環才能知道需要檢查的數組范圍。
在函數的聲明中也包含多維數組參數。定義一個3維數組 (tridimensional array) 的形式是:
`base_type[ ][depth][depth]`
例如,一個函數包含多維數組參數的函數可以定義為:
`void procedure (int myarray[ ][3][4])`
注意第一對括號[ ]中為空,而后面兩對不為空。這是必須的,因為編譯器必須能夠在函數中確定每一個增加的維度的深度。
數組作為函數的參數,不管是多維數組還是簡單數組,都是初級程序員容易出錯的地方。建議閱讀章節3.3, 指針(Pointers),以便更好的理解數組(arrays)是如何操作的。