第 8.2 章:陣列 (Arrays) - 整理你的數據

各位 IGCSE 電腦科學的同學大家好!陣列聽起來可能很複雜,但它們是你編程生涯中最實用的工具之一。

你可以把陣列想像成一個井然有序的檔案櫃或一排貼好標籤的置物櫃。與其建立數百個獨立的變數(例如 Student1, Student2, Student3...),你只需將所有相關的數據歸類在同一個名稱下。這樣處理大量資訊時,效率會大大提升,邏輯也更簡單清晰。

在本章中,我們將學習如何宣告這些結構化的儲存容器(陣列),更重要的是,如何利用迴圈(迭代)來儲存和讀取當中的數據。


1. 理解陣列的基本概念

什麼是陣列?

陣列是一種程式設計中使用的數據結構,用於儲存固定數目且類型相同的項目。

  • 固定長度 (Fixed Length): 一旦建立陣列,你就要定義它的大小,而在程式執行期間,這個大小通常是無法更改的。
  • 同質數據 (Homogeneous Data): 陣列內儲存的所有項目(稱為元素/Elements)必須屬於相同的數據類型(例如:全部都是 INTEGER,或是全部都是 STRING)。

關鍵術語:索引 (Index) 與元素 (Element)

要從陣列中獲取資訊(或存入資訊),你需要知道它的位置。我們使用索引 (Index)(也稱為下標/subscript)。

類比:想像一個有 10 個格子的置物櫃。陣列就是這一組置物櫃,而索引就是每個櫃門上的編號(1, 2, 3, ... 10)。櫃子裡的東西就是元素。

  • 元素 (Element): 實際儲存在陣列中某個插槽裡的數據。
  • 索引 (Index): 用於存取特定元素的位置編號。

關於索引的重要說明(教學大綱 8.2): 在電腦科學中,索引可以從 0 開始(以 0 為基底,Zero-based),也可以從 1 開始(以 1 為基底,One-based)。對於 IGCSE 虛擬碼,除非另有說明,我們通常假設採用以 1 為基底的索引,但請留意,有些程式語言是從 0 開始計算位置的。宣告語法允許你明確設定起始索引(下界/lower bound)和結束索引(上界/upper bound)。

快速複習:陣列特性

Array (陣列):All items (所有項目) 必須是同類型 (Alpha)。
Remember (記住):大小是 Rigid (剛性的/固定的)。
Read/write (讀寫):使用 Row number (列號/索引) 進行數據存取。


2. 一維 (1D) 陣列 (8.2.1)

一維陣列是最簡單的類型。它將數據儲存在單一行或列表中。

步驟 1:宣告一維陣列

當你宣告一個一維陣列時,必須聲明三件事:陣列名稱、索引範圍(下界:上界)以及元素的數據類型。

虛擬碼語法:

DECLARE <Identifier> : ARRAY[<Lower Bound>:<Upper Bound>] OF <data type>

範例:宣告一個名為 TestScores 的陣列,用以儲存 50 個 INTEGER 數值。索引範圍從 1 到 50。

DECLARE TestScores : ARRAY[1:50] OF INTEGER

步驟 2:存取與賦值(使用變數作為索引)

要讀取或寫入特定的元素,請使用陣列名稱,並在後方方括號 [ ] 內填入索引編號。

為了讓程式碼更靈活,在迴圈結構 (8.2.2) 中,應始終使用變數(例如 iIndex)作為索引。

存取範例:

OUTPUT TestScores[5] // 顯示儲存在第 5 個位置的分數

賦值範例:

TestScores[12] ← 95 // 將第 12 個位置的分數設為 95

步驟 3:使用迭代(迴圈)進行讀寫 (8.2.3)

由於陣列會連續儲存多個元素,我們幾乎總是使用迴圈(迭代)來高效處理它們。計數控制迴圈 (FOR loop) 是最適合的選擇,因為我們確切知道需要重複執行程序的次數(即陣列的大小)。

範例:填充一維陣列

這段虛擬碼會透過要求使用者輸入 50 次,來填滿 TestScores 陣列(大小為 50)。

DECLARE TestScores : ARRAY[1:50] OF INTEGER
DECLARE Counter : INTEGER

FOR Counter ← 1 TO 50
OUTPUT "Enter score number ", Counter
INPUT TestScores[Counter] // 使用 Counter 作為索引變數
NEXT Counter

重點總結(一維陣列)

一維陣列就是列表。我們使用單一變數作為索引,通常透過單個 FOR 迴圈來管理整個列表的數據輸入或讀取。


3. 二維 (2D) 陣列 (8.2.1)

如果一維陣列像清單,那麼二維陣列就像表格試算表。它有兩個維度:列 (Rows) 和欄 (Columns)。

類比:想像一個班級座位表。數據(學生姓名)是透過「行號」和「列號」來定位的。

步驟 1:宣告二維陣列

宣告二維陣列時,必須為兩個維度都指定索引範圍:即行與列。

虛擬碼語法:

DECLARE <Identifier> : ARRAY[<L1>:<U1>, <L2>:<U2>] OF <data type>

  • L1:U1 指的是行 (Rows) 的索引範圍(第一個維度)。
  • L2:U2 指的是欄 (Columns) 的索引範圍(第二個維度)。

範例:宣告一個名為 Board 的陣列來代表一個 8x8 的棋盤(儲存字元)。

DECLARE Board : ARRAY[1:8, 1:8] OF CHAR

步驟 2:存取二維陣列中的元素

要存取元素,你需要兩個以逗號分隔的索引值,放置在方括號內。習慣上,我們使用 [Row, Column] 的格式。

存取範例:

OUTPUT Board[2, 5] // 顯示儲存在第 2 行、第 5 欄的字元

賦值範例:

Board[8, 1] ← 'R' // 將第 8 行、第 1 欄的元素設為 'R' (車/Rook)

步驟 3:使用巢狀迭代處理二維陣列 (8.2.3)

由於二維陣列是一個網格,讀取或寫入*整個*陣列的數據需要用到巢狀迴圈 (Nested Loops)(迴圈中套著另一個迴圈)。

  • 外層迴圈通常控制行 (Rows)
  • 內層迴圈控制該特定行內的欄 (Columns)
範例:初始化二維棋盤陣列

這段虛擬碼會將整個 8x8 的 Board 陣列初始化,填入空白字元 (' ')。

DECLARE Board : ARRAY[1:8, 1:8] OF CHAR
DECLARE RowIndex : INTEGER
DECLARE ColIndex : INTEGER

FOR RowIndex ← 1 TO 8
FOR ColIndex ← 1 TO 8
Board[RowIndex, ColIndex] ← ' '
NEXT ColIndex
NEXT RowIndex

巢狀迴圈的步驟解析:

  1. RowIndex 從 1 開始。
  2. 內層迴圈 ColIndex 完整執行一遍(1 到 8)。它依序設定 Board[1, 1]Board[1, 8]
  3. 內層迴圈結束。
  4. 外層迴圈移至 NEXT RowIndex(現在是 2)。
  5. 內層迴圈再次完整執行(1 到 8)。它依序設定 Board[2, 1]Board[2, 8]
  6. 此過程不斷重複,直到 RowIndex 達到 8。
重點總結(二維陣列)

二維陣列就是表格。我們使用兩個索引變數(一個用於行,一個用於欄),並需要巢狀迴圈(通常是兩個 FOR 迴圈)來處理每一個元素。


4. 常見錯誤與記憶技巧

當心數據類型不匹配!

如果你宣告陣列為 OF INTEGER,就不能試圖在其中儲存 STRING 或 BOOLEAN 值。

錯誤範例:
DECLARE Ages : ARRAY[1:10] OF INTEGER
Ages[3] ← "Twenty-One" // 錯誤:嘗試將字串存入整數陣列。

偏差一錯誤 (Off-By-One Error)(程式設計師的夢魘)

當你的迴圈相對於陣列大小多跑了一次或少跑了一次時,就會發生這種情況。

範例: 如果你的陣列宣告為 ARRAY[1:10],它有 10 個位置(1 到 10)。如果你寫了一個迴圈 FOR i ← 0 TO 9,你將會存取到錯誤的儲存格(如果索引 0 是無效的,程式甚至可能會崩潰)。

提示: 務必讓你的迴圈界限完全匹配陣列的邊界。
DECLARE Names : ARRAY[1:10] 需要配合 FOR i ← 1 TO 10

你知道嗎?陣列與 RAM

當電腦為陣列分配記憶體時,它會劃出一塊連續的記憶體區塊,大小足以容納*所有*元素。這就是為什麼存取陣列非常快的原因;電腦只需根據起始位址和索引編號,就能精確知道每個元素位於何處。

陣列檢查清單

  • 宣告: 定義名稱、界限(起始與結束索引)以及數據類型。
  • 存取: 使用方括號 [ ] 加索引(二維陣列則用兩個索引)。
  • 處理: 使用迴圈(迭代)。一維陣列使用單個 FOR 迴圈;二維陣列使用巢狀 FOR 迴圈
  • 靈活性: 在迴圈內處理陣列時,務必使用變數(如計數器或迴圈索引)來存取元素。