109 身心障礙特考三等 資訊處理 程式語言 考古題詳解
第 一 題15 分
(一) 在程式語言中,什麼是懸置 else 的問題?(5 分)
(二) 近代高階程式語言怎麼解決懸置 else 的問題?(5 分)
(三) 在 C++ 語言中,寫程式可用什麼技巧避免懸置 else 的問題?(5 分)
登入後即可作答並保存紀錄。
核心觀念
**懸置 else(dangling else)**是指巢狀 if 敘述中,某個 else 究竟應該配對哪一個 if,在語法或閱讀上產生歧義的問題。
例如:
if (a)
if (b)
S1;
else
S2;
若語言文法沒有特別規定,else 可能被理解為配對外層的 if (a),也可能配對內層的 if (b)。這兩種解讀會造成不同的控制流程。
解題方法
本題分別考查三個層次:先定義歧義,再說明程式語言設計如何消除歧義,最後指出 C++ 程式設計者可採用的寫法。
(一)什麼是懸置 else 的問題?
當巢狀 if 敘述中出現 else,而前面有多個尚未配對的 if 時,若無明確規則決定配對對象,就會產生懸置 else 問題。
以上述程式為例,常見的兩種理解如下:
// else 配對內層 if
if (a) {
if (b)
S1;
else
S2;
}
// else 配對外層 if
if (a) {
if (b)
S1;
}
else {
S2;
}
兩者在條件不成立時執行的敘述不同,因此不是單純的排版問題,而是會影響程式語意的語法歧義。
(二)近代高階程式語言怎麼解決?
近代高階程式語言通常在文法中訂定明確的配對規則:else 配對最近一個尚未配對的 if。
第 二 題15 分
(一) 請比較 compiler 與 interpreter 的差別。(6 分)
(二) LISP、C、Python 三種語言,何者為 compiler 所編譯?何者為 interpreter 所執行?請說明。(9 分)
登入後即可作答並保存紀錄。
核心觀念
本題考查程式語言的執行方式,以及原始程式碼如何轉換成可執行的指令。
- Compiler(編譯器):先將原始程式碼整體翻譯成目標程式碼,例如機器碼或中介碼,再由電腦執行。編譯通常在執行前完成。
- Interpreter(直譯器):讀取程式碼並逐步解譯、執行;不一定會先產生獨立的機器碼檔案。執行時通常需要直譯器參與。
兩者的主要差異在於轉換與執行的時機、是否產生可獨立執行的目標程式,以及錯誤被發現的階段。實務上,語言與實作方式不必然一對一:同一種語言可有不同實作,也可能結合編譯與直譯。
解題方法
先比較兩種工具的處理流程,再依三種語言的典型實作判斷:
- 判斷是否先把整份原始程式轉成目標程式碼。
- 判斷執行時是否由直譯器逐步處理程式碼。
- 說明語言名稱與實作方式的關係,避免把「語言」誤當成唯一固定的執行方式。
(一)Compiler 與 Interpreter 的差別
| 比較項目 | Compiler(編譯器) | Interpreter(直譯器) |
|---|---|---|
| 處理方式 | 執行前先將原始程式碼編譯成目標程式碼 | 執行時讀取程式碼並逐步解譯、執行 |
| 執行所需 | 編譯完成後,目標程式可依其格式執行 | 通常需要直譯器在執行時處理程式碼 |
| 錯誤發現 | 編譯階段可先發現語法或型別等錯誤;執行期錯誤仍須執行時才會出現 | 執行到相關程式碼時才可能發現錯誤 |
| 執行效率 | 若已編譯成原生機器碼,執行通常較快 | 逐步解譯通常增加執行成本 |
| 可攜性 | 目標程式常與特定平台或執行環境有關 | 有相容直譯器的平台通常可執行相同程式碼 |
「Compiler 一定較快、Interpreter 一定較慢」是概括比較;實際效率仍取決於語言實作、執行環境與最佳化方式。
第 三 題30 分
(一) 請比較 concurrency 與 parallelism 方法的差別。(6 分)
(二) 什麼是 thread safe 的問題?請說明。(4 分)
(三) 有三個方法可以創造多執行緒,分別是:Threading、Fork、Multiprocessing。請比較這三種方法的差別。請從執行效率、memory sharing、thread safe 等方面來說明。(15 分)
(四) 請用 Python 並利用 multi-process 的方式,寫一段程式,同時下載兩部 videos,檔案名稱分別為 A.avi 與 B.avi,並顯示各自下載的時間。(5 分)
登入後即可作答並保存紀錄。
核心觀念
本題考查並行與平行的差異、共享狀態造成的執行緒安全問題,以及 Python 中不同多執行緒與多行程方式的特性。第(四)題則要以多行程同時下載兩個檔案,並分別計算下載時間。
- Concurrency(並行):多個工作在同一段時間內交錯推進。單核心也能藉由排程切換工作,呈現並行效果。
- Parallelism(平行):多個工作在同一時刻由不同處理器核心實際執行。通常需要多核心或多個處理器。
- Thread safe(執行緒安全):程式在多個執行緒同時存取共享資料時,仍能維持正確結果與一致狀態。若結果會因執行順序或時序而改變,就有競爭條件(race condition)。
(一)Concurrency 與 Parallelism
| 比較項目 | Concurrency(並行) | Parallelism(平行) |
|---|---|---|
| 核心概念 | 多個工作在一段時間內交錯進行 | 多個工作在同一時刻同時執行 |
| 單核心是否可行 | 可以,透過工作切換達成 | 無法在同一時刻執行多個工作 |
| 多核心的作用 | 可提升工作切換與處理能力 | 可讓不同工作真正同時執行 |
| 常見用途 | I/O 工作,例如等待網路或磁碟時切換到其他工作 | CPU 密集工作,例如大量計算 |
**解題方法:**先看「同一段時間內交錯推進」或「同一時刻實際同時執行」的差別。並行描述的是安排與管理多個工作的方式;平行描述的是多個工作是否真的同時占用不同運算資源。
(二)Thread safe 的問題
多個執行緒若同時讀寫共享資料,可能因執行順序不同而產生錯誤結果。以共享計數器 count 為例,執行 count += 1 可拆成讀取、加一、寫回等步驟;兩個執行緒若讀到相同的舊值,再各自寫回加一後的值,最後只增加一次,這就是競爭條件。
常見處理方式包括:
- 使用 lock(鎖) 或 mutex(互斥鎖),讓一次只有一個執行緒進入臨界區。
- 使用具原子性的操作或執行緒安全的資料結構。
- 避免共享可變狀態,改用訊息傳遞或各自持有資料。
判斷重點是:是否有共享資料、是否會被同時存取、存取是否包含修改。三者同時存在時,應考慮執行緒安全。
(三)Threading、Fork、Multiprocessing 比較
| 比較項目 | Threading | Fork | Multiprocessing |
|---|---|---|---|
| 執行單位 | 同一行程內的多個執行緒 | 複製目前行程,建立子行程 | 建立多個獨立子行程執行工作 |
| 記憶體 | 同一行程的執行緒共享記憶體 | 子行程初始狀態複製自父行程;通常採寫入時複製,之後各自有獨立位址空間 | 各行程有獨立記憶體;需透過 Queue、Pipe、共享記憶體等交換資料 |
| 執行效率 | 建立與切換成本低,適合 I/O 密集工作 | 建立行程有成本;初始複製常以寫入時複製降低成本 | 建立與溝通成本較高,可利用多核心處理 CPU 密集工作 |
| 平行能力 | CPython 的 GIL 使多個執行緒通常不能同時執行 Python 位元碼;I/O 等待時仍可切換 | 獨立行程可在多核心同時執行 | 獨立行程可在多核心同時執行 |
| Thread safe | 共享可變資料,需鎖或其他同步方式 | 行程間記憶體通常彼此隔離,較少遇到一般共享記憶體競爭;若使用共享記憶體仍需同步 | 預設記憶體隔離,通常較容易避免執行緒間的共享狀態問題;使用共享資源時仍需同步 |
| 常見用途 | 網路、檔案等 I/O 密集工作 | Unix 類系統上以複製行程方式建立子行程 | CPU 密集工作,或需要多行程執行的工作 |
第 四 題20 分
(一) 在程式語言中,有三種方式來定義字串的長度,分別為 static、limited dynamic length 和 dynamic with no maximum,請說明這三種方式的優缺點。(12 分)
(二) 對下列四種程式語言:C++、COBOL、JAVA、PERL,它們對字串長度處理的方式,各為哪一種?(8 分)
登入後即可作答並保存紀錄。
核心觀念
本題考查字串的長度在何時決定,以及字串能否增長。長度管理會影響記憶體配置、空間利用與字串操作彈性。
- Static(靜態長度):宣告時即決定固定長度,執行期間不能改變。
- Limited dynamic length(有限動態長度):宣告時設定最大長度,實際長度可在上限內變動。
- Dynamic with no maximum(無最大值的動態長度):實際長度可變,且沒有預先指定的最大長度;執行時依字串需求管理空間。
解題方法
依序判斷兩件事:
- 字串長度是否能在執行期間改變?
- 若能改變,是否有事先設定的最大長度?
長度固定,屬於 static;長度可變但有上限,屬於 limited dynamic length;長度可變且無預設上限,則屬於 dynamic with no maximum。
三種方式的優缺點
| 方式 | 優點 | 缺點 |
|---|---|---|
| Static | 長度固定,記憶體配置與存取方式簡單;執行期間不需因字串長度變化而重新配置空間。 | 不足長度時無法容納較長內容;若實際字串較短,未使用的空間仍被保留,造成浪費。 |
| Limited dynamic length | 實際長度可變,比固定長度更能配合資料;因有上限,所需空間可預先掌握。 | 超過最大長度時無法直接容納,必須截斷、報錯或採取其他處理;配置的最大空間未必都會用到。 |
| Dynamic with no maximum | 字串可依實際需求增長,不必受預先指定的最大長度限制,適合長度差異大的文字資料。 | 執行時須管理配置與調整,處理較複雜;若字串大量增長,會增加記憶體需求及管理成本。 |
各語言的字串長度處理方式
第 五 題20 分
請比較下列五種語言設計方式的差別:Imperative Programming、Declarative Programming、Procedural Programming、Object-Oriented Programming、Functional Programming。(20 分)
登入後即可作答並保存紀錄。
核心觀念
本題比較五種程式設計典範,重點在於辨別程式主要描述的是「如何執行」、「要得到什麼結果」,或是如何組織資料與運算。這些分類彼此並非完全互斥:例如程序式程式設計通常屬於命令式的一種;物件導向與函數式則各有不同的組織方式與運算觀點。
解題方法
依序比較各典範的兩個面向:
- 程式描述什麼:描述執行步驟,還是描述問題與結果。
- 如何組織程式:以程序、物件,或函數為主要單位。
| 設計方式 | 核心概念 | 程式主要描述方式 | 常見特徵 |
|---|---|---|---|
| 命令式(Imperative) | 指示電腦如何完成工作 | 一連串指令與狀態變更 | 指派、條件、迴圈 |
| 宣告式(Declarative) | 描述要達成什麼結果 | 關係、規則或條件 | 執行細節由系統處理 |
| 程序式(Procedural) | 將工作拆成程序或副程式 | 呼叫程序,按步驟處理 | 參數傳遞、程序分解 |
| 物件導向(Object-Oriented) | 以物件封裝資料與行為 | 物件互動與方法呼叫 | 封裝、繼承、多型 |
| 函數式(Functional) | 以函數運算與組合表達計算 | 函數套用與資料轉換 | 避免可變狀態、副作用 |
各種設計方式說明
1. 命令式程式設計
命令式程式設計以指令描述程式的執行過程,程式會逐步改變變數或系統狀態。設計者需要明確指定操作順序,以及如何透過條件判斷、迴圈與指派完成工作。
例如計算陣列總和時,命令式程式會設定累加器,逐一讀取陣列元素並更新累加器。
2. 宣告式程式設計
宣告式程式設計著重表達欲達成的結果、資料關係或必須符合的條件,不必逐項指定處理步驟。系統或執行環境負責決定如何求得結果。
例如 SQL 查詢通常描述要取得哪些資料及篩選條件,由資料庫系統決定查詢執行方式。宣告式程式仍可能由系統依某種步驟執行;差別在於程式設計者不以逐步命令為主要表達方式。