歡迎來到子程式:模組化程式設計的力量!

各位未來的電腦科學家好!本章節將深入探討程式設計師工具箱中最強大的工具之一:子程式 (Subroutines)

如果你曾經試過撰寫長篇大論的文章,或是拼裝一個巨大的樂高城堡,你一定知道一次過處理所有事情會有多混亂。子程式的作用就像是將巨大的任務拆解成一個個小巧、易於管理的「迷你任務」。

為什麼這很重要? 理解子程式是編寫專業、可重複使用且易於除錯的程式碼的關鍵。不用擔心一開始覺得難以理解;我們會一步一步拆解這些概念!


什麼是子程式?(核心概念)

子程式(有時稱為模組、方法、函數或程序)只是一段設計用來執行特定任務的獨立程式碼區塊。

將編寫程式想像成建造房屋:

  • 如果沒有子程式,你必須把鋪設地基、安裝水管、佈線和鋪設屋頂的指令全部寫在同一個巨大又混亂的清單裡。
  • 有了子程式,你可以建立分開的說明書:「建造地基」「安裝電線」「粉刷牆壁」。你的主程式只需在需要時呼叫這些說明書即可。

為什麼要使用子程式?主要優點

使用子程式是模組化程式設計 (Modular Programming) 的基礎。以下是你需要知道的三大優點:

  1. 可重用性 (Reusability): 如果你的程式需要計算稅款 20 次,你不需要編寫 20 次計算程式碼。你只需寫一個子程式(函數),然後呼叫它 20 次。這能節省工作量並縮減程式碼長度。
  2. 可維護性與測試 (Maintainability and Testing): 如果稅款計算出現錯誤 (Bug),你只需要在一個地方(即子程式內部)進行修正。測試一個小型、獨立的程式碼區塊也比測試整個龐大的程式要容易得多。
  3. 結構化 (Structure): 這讓程式碼更易於閱讀和理解。當別人檢視你的主程式時,他們會看到高階的任務(例如 ProcessPayment()),而不是數百行的計算過程。

關鍵總結: 子程式讓你能透過將龐大的程式拆解成細小、具名且可重複使用的組件,來管理複雜度。


兩種子程式

在程式設計中,根據是否需要將數值傳回給主程式,子程式分為兩大類。

1. 程序 (Procedures - 「執行者」)

程序是一組僅執行指令的序列。它會完成一項任務,但不會將計算結果傳回給呼叫它的位置。

  • 目的: 執行動作,例如顯示文字、將資料儲存到檔案,或在螢幕上繪圖。
  • 例子: 名為 DisplayMenu() 的程序會在螢幕上顯示選項,但它不會進行計算或傳回數值答案。

程式碼範例(偽代碼):
PROCEDURE DisplayWelcomeMessage()
PRINT "歡迎來到本程式!"
END PROCEDURE

2. 函數 (Functions - 「計算者」)

函數是一組執行任務並計算或獲取數值的指令序列,隨後會使用 RETURN 語句將結果傳回給主程式。

  • 目的: 計算、提取或確定特定的單一結果。
  • 例子: 名為 CalculateArea() 的函數會獲取長度和寬度,並將計算出的面積傳回給主程式。

程式碼範例(偽代碼):
FUNCTION CalculateTax(Price)
Tax = Price * 0.20
RETURN Tax
END FUNCTION

關鍵區別:傳回數值

程序與函數之間的區別,完全取決於傳回值 (Return Value)

程序: 執行指令。(無傳回值)
函數: 執行指令提供單一結果。(必須有傳回值)

🔥 記憶小撇步: 試著聯想數學函數 \( f(x) \)。它總是根據輸入值 (\( x \)) 給出一個答案(傳回值)。

快速複習: 如果你需要將答案儲存到變數中(例如 Result = Calculate(...)),你需要使用函數。如果你只需要執行某個動作(例如列印文字),請使用程序


傳遞資料:參數與引數

當子程式每次呼叫時都能處理不同的資料,它才最具用處。這可以透過參數 (Parameters)引數 (Arguments) 來達成。

類比:訂披薩

想像子程式是一台「披薩製作機」:

  • 機器定義(子程式碼): 它需要預留位置,說明要製作哪種披薩(例如:配料1、配料2、尺寸)。這些預留位置就是參數 (Parameters)
  • 點餐單(呼叫子程式): 當你呼叫機器時,你在上面寫下細節:義式臘腸、蘑菇、大份。這些實際的數值就是引數 (Arguments)

定義參數(預留位置)

參數是子程式定義(標頭)中列出的變數。它們作為暫時的區域變數,用來存放呼叫該程序時傳入的數值。

偽代碼範例(定義參數: ItemCost Quantity):
FUNCTION CalculateTotal(ItemCost, Quantity)
Total = ItemCost * Quantity
RETURN Total
END FUNCTION

傳遞引數(實際數值)

引數是子程式執行(呼叫)時實際供給的數值或變數。

偽代碼範例(傳入引數: 5.00 3 來呼叫函數):
Price_per_unit = 5.00
Number_bought = 3
My_Bill = CalculateTotal(Price_per_unit, Number_bought)

當此函數執行時,ItemCost 變為 5.00,而 Quantity 變為 3。

你知道嗎? 將參數和引數的順序弄錯(例如把長度和寬度互換)是非常常見的錯誤,這會導致邏輯錯誤!


變數範疇 (Variable Scope:區域與全域)

當你建立一個變數時,你需要知道在程式的哪個位置可以存取或更改該變數。這種存取權限稱為範疇 (Scope)

區域變數 (Local Variables - 「私人辦公室」)

區域變數是定義在子程式(程序或函數)內部的變數。

  • 存取權限:能在定義它的子程式內部使用。
  • 生命週期: 它僅在子程式執行期間存在。一旦子程式執行完畢,區域變數就會被銷毀(遺忘)。

這樣做更安全,因為不同的子程式可以使用通用的變數名稱(如 'i' 或 'count'),而不會意外影響到其他子程式中的變數。

範例:在下方的函數中,Total 是一個區域變數:
FUNCTION CalculateTotal(Cost, Qty)
Total = Cost * Qty <-- 此變數僅在此函數內部存在!
RETURN Total
END FUNCTION

全域變數 (Global Variables - 「公共佈告欄」)

全域變數是定義在任何子程式外部的變數,通常在程式的最開頭處定義。

  • 存取權限: 程式的任何部分皆可讀取和修改它,包括所有的程序和函數。
  • 注意: 雖然方便,但過度依賴全域變數會使程式更難除錯,因為程式的任何部分都可能意外地更改它們。現代程式設計習慣通常建議盡量減少全域變數的使用。

範例:TAX_RATE 可能是一個全域變數:
TAX_RATE = 0.20 <-- 定義在頂部;隨處可存取。

FUNCTION ApplyTax(Price):
TaxAmount = Price * TAX_RATE <-- 存取全域變數
RETURN TaxAmount
END FUNCTION

避免常見錯誤:範疇混淆

新手常見的錯誤是嘗試在定義該變數的子程式外部使用區域變數。

如果你呼叫一個名為 GetUserAge() 的程序,該程序內建立的變數(例如 UserAge)在程序結束時就會被遺忘,除非該數值有明確地透過 RETURN 傳回(如果是函數),或者被儲存在全域變數中。

範疇總結

區域 (Local): 子程式的私有變數。非常適合用於暫時性的計算。
全域 (Global): 全程式的公開變數。請謹慎使用,通常用於常數(如 PI 或稅率 TAX_RATE)。


章節總結與心得

你已經掌握了結構化程式設計的核心概念!請記住:

1. 子程式將複雜的任務拆解成更簡單、可重用的區塊。

2. 如果你需要執行動作(例如列印),請使用程序 (Procedure)

3. 如果你需要計算並 RETURN 一個結果(例如計算稅款),請使用函數 (Function)

4. 參數 (Parameters) 是預留位置;引數 (Arguments) 是傳入的實際數值。

5. 範疇 (Scope) 決定了變數的使用範圍—除非必須設為全域變數,否則為了安全起見,請保持變數為區域變數

請持續練習呼叫與定義這些子程式。編寫乾淨、模組化的程式碼是一位優秀程式設計師的標誌!