語法書 / AA 競程語法書 上冊 / 第六單元 / 一維陣列:宣告與使用

6.1 一維陣列:宣告與使用

圖 6-1:陣列的記憶體佈局

陣列就像「編號的盒子」。一個陣列名稱 a 代表一整列盒子,每個盒子用數字編號,你可以用 a[編號] 取得或修改裡面的值。

這排盒子在記憶體裡是連續排在一起的,一個接一個、中間沒有空隙。所以電腦只要知道開頭在哪、每個盒子多大,就能直接算出 a[i] 在哪一格,不必從頭一個一個數過去。

陣列的宣告格式:

資料型態 陣列名稱[大小];

例如:

int a[5];  // 宣告一個能儲存 5 個 int 的陣列

關鍵規則:

  1. 陣列名稱命名:和變數一樣,用字母/數字/底線組成,首字不能是數字
  2. 大小必須是常數:不能用變數。int a[n]; ✗、int a[5];
  3. 索引從 0 開始a[5] 有 5 個元素:a[0], a[1], a[2], a[3], a[4]
    • a[5] 不存在,會造成越界存取,結果不可預測
  4. 用運算式當索引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 的意思是「宣告後不能再改的變數」。三個規則:

  1. 宣告時一定要初始化——const int MAX_N; 是編譯錯誤
  2. 之後任何修改它的嘗試,編譯器都會直接報錯——幫你把關
  3. 一處定義、全處使用——題目上限改了,只改這一行

命名也有慣例:const 常數的名稱全部用大寫,多個單字之間用底線隔開(像上面的 MAX_N)。一般變數用小寫、常數用大寫,掃過程式碼時一眼就能認出「這個值不會變」。

從下一節開始,本書所有範例都用這種寫法開陣列。照著養成習慣:宣告陣列時先想「題目上限多少」,用 const 開好開滿。(const 也能幫其他固定數字取名字,之後會常用到。)

陣列的排版

陣列的存取也有幾個好讀的小習慣:

// ✓ 好的排版
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.56.9 學到時再講。)

動手試試看:把程式碼中的 a[2*2-1] 改成 a[2*3](即訪問 a[6]),看看會發生什麼。想想看為什麼會出問題?