6.1 一維陣列:宣告與使用
陣列就像「編號的盒子」。一個陣列名稱 a 代表一整列盒子,每個盒子用數字編號,你可以用 a[編號] 取得或修改裡面的值。
這排盒子在記憶體裡是連續排在一起的,一個接一個、中間沒有空隙。所以電腦只要知道開頭在哪、每個盒子多大,就能直接算出 a[i] 在哪一格,不必從頭一個一個數過去。
陣列的宣告格式:
資料型態 陣列名稱[大小];
例如:
int a[5]; // 宣告一個能儲存 5 個 int 的陣列
關鍵規則:
- 陣列名稱命名:和變數一樣,用字母/數字/底線組成,首字不能是數字
- 大小必須是常數:不能用變數。
int a[n];✗、int a[5];✓ - 索引從 0 開始:
a[5]有 5 個元素:a[0], a[1], a[2], a[3], a[4]a[5]不存在,會造成越界存取,結果不可預測
- 用運算式當索引:
a[2*3]等於a[6]、a[i+1]等
¶範例程式碼
#include<iostream>
using namespace std;
int main() {
// 宣告一個大小為 5 的 int 陣列
int a[5];
// 用亂序順序指派數值,索引值 i 的元素被設為 i+1
a[3] = 4;
a[0] = 1;
a[2] = 3;
a[4] = 5;
a[1] = 2;
// 用索引值存取和輸出
cout << a[2] << '\n'; // 輸出 3
cout << a[2 * 2 - 1] << '\n'; // 2*2-1=3,輸出 a[3]=4
cout << a[a[0]] << '\n'; // a[0]=1,輸出 a[1]=2
return 0;
}
執行結果:
3
4
2
¶用 const 常數指定陣列大小
與其在陣列大小的位置寫死一個「魔法數字」,競程慣例是宣告一個 const 常數來當大小:
const int MAX_N = 100005; // 題目 n ≤ 10^5,上限再加一點
int a[MAX_N]; // 用 const 常數當大小,合法
const 的意思是「宣告後不能再改的變數」。三個規則:
- 宣告時一定要初始化——
const int MAX_N;是編譯錯誤 - 之後任何修改它的嘗試,編譯器都會直接報錯——幫你把關
- 一處定義、全處使用——題目上限改了,只改這一行
命名也有慣例:const 常數的名稱全部用大寫,多個單字之間用底線隔開(像上面的 MAX_N)。一般變數用小寫、常數用大寫,掃過程式碼時一眼就能認出「這個值不會變」。
從下一節開始,本書所有範例都用這種寫法開陣列。照著養成習慣:宣告陣列時先想「題目上限多少」,用 const 開好開滿。(const 不只能開陣列大小——本節最後就是它的另一個常見用途。)
¶另一個常用的 const:無限大 INF
const 的第二個常見用途,是幫大到不可能被超過的值取個名字。6.4 找最小值時要先給一個起始值,而那個起始值必須比任何可能的答案都大——競程慣例把它叫做 INF(infinity,無限大):
const int INF = 1000000000; // 十億:int 裝得下,再加一點也不會爆
const long long INF_LL = 1000000000000000000LL; // 10^18,答案可能超過 int 時用
(後面那個 LL 後綴是 2.8 教過的「這個數字請當成 long long」。)
為什麼不乾脆用 2.3 的 INT_MAX?因為起始值常常還要參與運算:INT_MAX 再加 1 當場溢位(2.9),十億再加個幾百萬卻還穩穩待在 int 範圍內。留餘裕,才不會在比較的過程中自己爆掉。
¶陣列的排版
陣列的存取也有幾個好讀的小習慣:
// ✓ 好的排版
cout << a[i] << " " << a[i + 1];
// ✗ 不好的排版
cout << a[ i ] << " " << a[i+1];
| 規則 | ✓ 好的做法 | ✗ 不好的做法 | 為什麼 |
|---|---|---|---|
| 中括號內不加空格 | a[i] |
a[ i ] |
索引緊貼中括號,就像數學的下標 |
| 索引運算式加空格 | a[i + 1]、a[n - 1] |
a[i+1] |
運算子周圍加空格,長一點的索引也看得清楚 |
(初始化大括號、多維陣列的排版,分別等 6.5 和 6.9 學到時再講。)
動手試試看:把程式碼中的 a[2*2-1] 改成 a[2*3](即訪問 a[6]),看看會發生什麼。想想看為什麼會出問題?