AS Level 電腦科學 (9618) 溫習筆記:程式編寫 (第 11 及 12 章)
你好,未來的程式設計師!歡迎來到電腦科學的核心:**程式編寫 (Programming)**。本章將帶領大家從算法 (第 9 章) 和數據結構 (第 10 章) 的理論世界,邁向將這些構思轉化為實際解決方案的實踐技巧。
我們將學習編寫代碼的基本構件、如何有效地組織程式,以及規劃、測試和維護穩健軟件所需的關鍵步驟。
如果覺得寫代碼很困難,請不用擔心,我們會將所有內容拆解,一步步教學。掌握這些技能對於 Paper 2 至關重要,屆時你將需要運用虛擬代碼 (Pseudocode) 來解決問題!
11. 程式編寫
11.1 程式編寫基礎
本節涵蓋了我們用來向電腦發送指令的核心規則與工具。
變數、常數與數據類型
把電腦記憶體想像成一個巨大的儲物櫃。
- 變數 (Variable): 一個已命名的儲存位置,其值在程式執行期間**可以改變**。
- 常數 (Constant): 一個已命名的儲存位置,其值是**固定**的,在執行期間不能更改。使用常數能讓代碼更清晰、更安全 (防止意外更改關鍵數值)。
宣告變數或常數時,必須指定其數據類型 (Data Type)。這告訴電腦預期接收什麼類型的資訊,以及需要分配多少空間。
AS Level 常見的數據類型 (及其虛擬代碼表示):
- INTEGER: 整數 (例如:5, -100)。常用於計數器或分數。
- REAL: 包含小數部分的數值 (例如:3.14, 0.5)。
- CHAR: 單一字母、數字或符號 (例如:'A', '7', '$')。
- STRING: 字元序列 (例如:"Hello World")。
- BOOLEAN: 僅包含兩個值:TRUE 或 FALSE。非常適合用於標記 (flags) 或條件判斷。
宣告與賦值 (Declaration and Assignment):
我們在程式或模組的開頭宣告常數和變數。
-
宣告 (變數):
DECLARE StudentName : STRING -
宣告 (常數):
CONSTANT PI = 3.14 -
賦值 (給予數值):
StudentName ← "Alex"
常見誤區: 切勿混淆賦值 (`←`) 與比較 (`=`)。在虛擬代碼中,`←` 是將數值「放入」變數中。
輸入、輸出與運算式
程式必須與用戶互動 (輸入) 並顯示結果 (輸出)。
-
輸入:
INPUT Age(從鍵盤讀取數據並存入變數 Age)。 -
輸出:
OUTPUT "Your age is ", Age(在控制台顯示文字及 Age 的值)。
運算式 (Expression) 結合了數值、變數與運算子 (算術或邏輯) 來產生一個結果。
-
算術運算子:
+,-,*,/,DIV(整數除法),MOD(取餘數)。 -
邏輯運算子:
AND,OR,NOT。
你知道嗎? 使用內建函數 (如計算平方根 SQRT(X)) 和程式庫常式 (預先編寫的代碼塊) 可為程式設計師節省大量時間,並使代碼更可靠,因為這些函數已經過測試並證明正確。
11.2 結構 (控制結構)
任何算法的三個基本構件是順序 (Sequence)、選擇 (Selection) 和迭代 (Iteration)。我們使用控制結構來實現選擇和迭代。
選擇 (決策制定)
選擇結構允許程式根據條件 (布林運算式) 選擇執行路徑。
1. IF...THEN...ELSE (及嵌套 IF)
- 用於在兩個或多個結果之間進行簡單選擇時。
-
虛擬代碼範例:
IF Score > 75 THEN
OUTPUT "Distinction"
ELSE
OUTPUT "Pass"
ENDIF
2. CASE 結構
- 當根據單一變數的值有多個互斥的結果時使用。這比使用多層嵌套的 IF 語句更整潔。
-
虛擬代碼範例:
CASE DayOfWeek OF
1: OUTPUT "Monday"
5: OUTPUT "Friday"
OTHERWISE OUTPUT "Weekend or other day"
ENDCASE
迭代 (循環/重複)
迭代允許代碼塊重複執行。選擇正確的循環結構對於編寫高效代碼非常重要。
1. 計數控制循環 (FOR 循環)
- 當你知道循環需要執行確切次數時使用。
-
虛擬代碼範例:
FOR Counter ← 1 TO 10
2. 前置條件循環 (WHILE 循環)
- 在執行循環主體之前先檢查條件。循環可能會執行零次或多次。
- 當終止條件取決於外部因素 (如用戶輸入或檔案狀態) 時使用。
-
虛擬代碼範例:
WHILE InputValue <> -1 DO
// 循環主體
ENDWHILE
3. 後置條件循環 (REPEAT UNTIL 循環)
- 在執行循環主體之後檢查條件。該循環保證至少執行一次。
- 常考用於確保有效輸入 (不斷提示用戶直至輸入可接受的數據)。
-
虛擬代碼範例:
REPEAT
INPUT Password
UNTIL Password = "secret"
如何選擇循環:
如果問題需要重複特定次數 (例如輸入 5 個分數),使用 FOR 循環。如果必須確保至少執行一次 (例如驗證輸入),使用 REPEAT UNTIL。如果循環可能一次都不需要執行 (例如處理空檔案中的記錄),則使用 WHILE。
11.3 結構化程式編寫 (程序與函數)
結構化程式編寫涉及將大型程式分解為較小、獨立的模組。這使得代碼編寫、除錯及維護更容易。這些模組稱為**子程式 (Subroutines)**:程序 (Procedures) 和函數 (Functions)。
程序 (做某事的子程式)
程序是一個已命名的代碼塊,用於執行特定任務,但不一定向主程式回傳值。
- 適合用途: 涉及輸入/輸出或直接修改變數的任務 (例如將數據儲存到檔案,或打印選單)。
-
語法: 使用
PROCEDURE定義,並透過名稱直接呼叫。
函數 (計算並回傳值的子程式)
函數是一個已命名的代碼塊,用於計算數值並將該值回傳給呼叫它的運算式。
- 適合用途: 數學計算、字串處理或檢查條件 (例如計算稅款,或查找名稱長度)。
-
語法: 使用
FUNCTION定義,並在運算式中使用,回傳值會取代函數呼叫的位置。
參數與引數
為了讓程序和函數更靈活,我們透過參數 (Parameters) 傳遞數據。
- 參數 (Parameter): 定義在程序/函數標頭中,用於接收數據的識別符。
- 引數 (Argument): 呼叫程序/函數時實際傳遞的數值或變數。
參數傳遞方式分為兩種:
1. 傳值 (Pass By Value)
- 傳遞的是引數的「副本」。
- 在子程式內部對參數所作的任何更改,都不會影響主程式中的原始變數 (引數)。
- 比喻: 給某人一份你的筆記影印本。他們可以在影印本上亂畫,但你的原始筆記保持原樣。
2. 傳址 (Pass By Reference)
- 傳遞的是引數的記憶體位址 (參照)。
- 在子程式內部對參數所作的任何更改,都會影響主程式中的原始變數。
- 比喻: 給某人你儲物櫃的真實鑰匙。他們可以永久更改裡面的內容。
12. 軟件開發
編寫代碼 (第 11 章) 只是工作的一部分。第 12 章探討建構大型、可靠軟件系統所需的結構與紀律。
12.1 程式開發生命週期 (PLC)
程式開發生命週期 (Program Development Life Cycle, PLC) 是一套結構化的框架,描述了開發、維護及最終棄用軟件系統所需的步驟。其目的是確保質量、管理複雜性並滿足用戶需求。
PLC 階段
- 分析 (Analysis): 定義問題並識別用戶需求。(系統需要做什麼?)
- 設計 (Design): 規劃解決方案結構、算法及介面。(系統將如何實現?)
- 編碼 (Coding): 編寫程式代碼。
- 測試 (Testing): 檢查程式錯誤並確保其滿足要求。
- 維護 (Maintenance): 在部署後修復程式錯誤並進行更新。
開發生命週期模型
不同類型的程式需要不同的處理方法。
1. 瀑布模型 (Waterfall Model)
- 原則: 每個階段必須在下一個階段開始前完成,嚴格向下流動。
- 優點: 簡單、結構高度化,易於管理小型且目標明確的項目。
- 缺點: 非常缺乏彈性;如果後期需求變更,回溯成本極高且困難。
2. 迭代模型 (Iterative Model)
- 原則: 項目在小型、重複的循環 (迭代) 中開發。早期建立原型並隨時間精煉。
- 優點: 允許早期用戶反饋,並能輕鬆適應變更的需求。
- 缺點: 若管理不當,可能導致「範圍蔓延」(項目無止境地擴大)。
3. 快速應用程式開發 (RAD)
- 原則: 透過持續的用戶參與快速建立原型,減少規劃時間。
- 優點: 對於用戶介面至關重要且需求稍具彈性的項目,開發速度非常快。
- 缺點: 不適用於極其複雜、大型的系統,或需要嚴格保安/安全性的情況 (如航空控制軟件)。
12.2 程式設計
設計階段使用工具在編寫任何一行代碼前規劃程式結構。
結構圖 (Structure Charts)
結構圖是一種層次化圖表,用於**由上而下設計 (top-down design)**,將問題分解為更小、易於管理的子任務 (模組、程序或函數)。
- 目的: 顯示程式的整體結構以及各模組間的關係。
- 關鍵特徵: 明確顯示模組間傳遞的**參數/數據** (數據箭頭用圓形表示,控制旗標/狀態則用菱形表示)。
狀態轉移圖 (State-Transition Diagrams)
狀態轉移圖記錄了在不同狀態下運行的算法。
- 目的: 用於建模當前動作取決於過去輸入歷程的系統 (例如交通燈、自動售賣機、簡單登入系統)。
- 結構: 圓形表示**狀態 (States)**,箭頭表示**轉移 (Transitions)** (觸發狀態改變的動作或輸入)。
12.3 程式測試與維護
無法正確運作的程式是毫無用處的。本節探討如何發現、預防及修復錯誤。
錯誤類型
- 語法錯誤 (Syntax Error): 違反程式語言的語法規則。翻譯器 (編譯器/直譯器) 會捕捉到這些錯誤。
- 邏輯錯誤 (Logic Error): 程式成功執行,但產生錯誤的輸出,因為算法邏輯不正確。翻譯器無法捕捉這些錯誤。
- 執行時期錯誤 (Run-time Error): 在程式執行時發生,導致程式崩潰或異常停止。(例如:除以零,或嘗試存取不存在的陣列索引)。
測試策略與數據
測試數據的選擇:
- 正常數據 (Normal Data): 預期輸入的數據 (在可接受範圍內)。
- 極限/邊界數據 (Extreme/Boundary Data): 可接受範圍臨界點的數據。這是最容易隱藏錯誤的地方!
- 異常數據 (Abnormal Data): 意圖讓程式崩潰的無效數據 (例如格式錯誤、超出範圍)。
測試方法
- 乾跑 (Dry Run): 使用追蹤表手動逐行執行代碼 (通常由開發者在紙上完成)。
- 走查 (Walkthrough): 開發團隊由作者帶領,手動逐行檢查代碼。
- 白盒測試 (White-Box Testing): 基於了解程式內部結構與路徑進行測試。確保每一行代碼至少執行一次。
- 黑盒測試 (Black-Box Testing): 僅基於規格說明與預期輸出進行測試,不考慮內部代碼結構。
- 整合測試 (Integration Testing): 測試各模組「共同」運作時是否正確。
- Alpha 測試: 發布前由內部人員測試。
- Beta 測試: 發布前由真實用戶在現實環境中測試。
- 驗收測試 (Acceptance Testing): 客戶或終端用戶確認系統滿足所有合約需求的正式測試。
- 虛設模組 (Stub): 測試期間使用的臨時佔位模組,用以模擬尚未編寫的模組功能。
程式維護
- 更正性維護 (Corrective): 修復使用後發現的錯誤與程式缺陷。
- 適應性維護 (Adaptive): 修改系統以適應環境變化 (如作業系統升級)。
- 完善性維護 (Perfective): 提升性能、效率或可維護性 (如優化慢速代碼)。