107 高普考高考三級 資訊處理 程式語言 考古題詳解
第 一 題20 分
以下二小題是完整的 C/C++ 程式碼,請回答執行的結果為何?(每小題 10 分,共 20 分)
(一)
#include <stdio.h> #include <stdlib.h>
int recFun(int);
int main(void) { printf("%d\n", recFun(12345));
return 0;
}
int recFun(int n) { if (n < 10) return n; else return recFun(n / 10) + n % 10; }
(二)
#include <iostream> #include <cstdlib> #include <string> using namespace std;
struct data { string name; int a, b; };
void fun1(struct data), fun2(struct data *), fun3(struct data);
int main(void) { struct data man = {"John", 11, 33}, lady = {"Linda", 22, 44};
cout << "After process..." << endl;
fun2(&man);
fun3(lady);
fun1(man);
fun1(lady);
return 0;
}
void fun1(struct data in) { cout << "Name: " << in.name << endl; cout << "a=" << in.a << ", "; cout << "b=" << in.b << endl; }
void fun2(struct data *ptr) { int tmp;
tmp = ptr->a;
ptr->a = ptr->b;
ptr->b = tmp;
}
void fun3(struct data in) { int tmp;
tmp = in.a;
in.a = in.b;
in.b = tmp;
}
登入後即可作答並保存紀錄。
核心觀念
- 遞迴函數(Recursive Function):函式在執行過程中直接或間接呼叫自身。一個正確的遞迴函式必須具備「終止條件(Base Case)」與「遞迴關係(Recursive Step)」,以避免無窮遞迴導致堆疊溢位(Stack Overflow)。
- 整數除法與餘數運算:在 C/C++ 中,整數除法
/會無條件捨去小數點(截尾取整);餘數運算子%可取出被除數除以除數後的餘數。
n % 10:取得十進位整數 的個位數字(最低有效位)。n / 10:消除十進位整數 的個位數字,將高位數字向右位移一位。
解題方法
本題定義遞迴函式 recFun(int n) 如下:
- 終止條件:當 時,直接回傳 (已達最高位的單一數字)。
- 遞迴步驟:當 時,回傳
recFun(n / 10) + n % 10。
計算 recFun(12345) 的呼叫堆疊(Call Stack)展開與回溯推導過程如下:
- 呼叫展開階段(Push to Stack):
- :此時引數 ,符合終止條件,直接回傳 。
- 遞迴回溯計算階段(Pop from Stack):
main 函式執行 printf("%d\n", recFun(12345));,將回傳值 格式化為整數輸出並換行。
解題技巧
- 功能特徵判斷:看到
(n / 10)搭配(n % 10),即可判定此函式的語意為「十進位整數各個位數加總(Sum of Digits)」。 - 快速驗算:直接將各個位數相加: 考場上只需花 3 秒即可心算求出答案,再行書寫呼叫過程以確保無誤。
【答案】
15
第(二)小題
核心觀念
- 參數傳遞機制(Parameter Passing Mechanisms):
- 傳值呼叫(Call by Value):呼叫端將實引數(Actual Parameter)的值複製一份給函式的虛引數(Formal Parameter)
第 二 題10 分
以下是完整的 Python 程式碼,請說明此程式的詳細功能為何?(10 分)
import os.path
file1 = input("Input a file name: ") file2 = input("Input the other file name: ")
while not os.path.isfile(file1): print("The file does not exist!") file1 = input("Input a file name again: ")
while os.path.isfile(file2): answer = input("The file existed, Overwrite it? y/n? ") if answer == 'n' or answer == 'N': file2 = input("Input a file name again: ") else: break
fileObject1 = open(file1, "r") fileObject2 = open(file2, "w")
content = fileObject1.read() fileObject2.write(content)
fileObject1.close() fileObject2.close()
登入後即可作答並保存紀錄。
核心觀念
本題評量 Python 基礎程式設計中的檔案輸入/輸出(File I/O)與使用者互動流程控制,核心涵蓋以下四大觀念:
- 檔案狀態檢查與
os.path模組: 使用os.path.isfile(path)函式判斷指定路徑是否為已存在的一般檔案(Regular File),回傳布林值(True或False)。 - 防呆驗證與迴圈控制(Validation Loops):
- 藉由
while not ...迴圈阻擋無效輸入,強制使用者直到輸入合法資料才能繼續。 - 藉由條件分支(
if-else)搭配break陳述式,控制是否跳出迴圈或重新請求輸入。
- 檔案讀寫模式(File Access Modes):
open(file, "r"):以唯讀(Read)模式開啟檔案,若檔案不存在會拋出FileNotFoundError。open(file, "w"):以寫入(Write)模式開啟檔案,若檔案已存在會將原內容完全清空(截斷,Truncate)並覆寫;若檔案不存在則會建立新檔。
- 資源存取與釋放(File Resource Management):
透過
read一次性讀取全檔內容至記憶體字串,透過write寫入內容,最後呼叫close關閉檔案串流以釋放作業系統之檔案描述子(File Descriptor)。
解題方法
本題要求說明「此程式的詳細功能」。解題切入點應採由上而下(Top-down)分段剖析程式執行流程,先釐清各區塊的防呆與邏輯處理,再彙整出整體的系統功能:
- 第一階段:取得使用者輸入檔名
- 提示使用者輸入來源檔案名稱(
file1)與目的檔案名稱(file2)。
- 第二階段:來源檔案存在性防呆(Source File Validation)
- 判斷
file1是否存在。若不存在,進入while迴圈印出警告訊息"The file does not exist!",並要求使用者重新輸入,直到輸入一個確實存在的檔案為止。
- 第三階段:目的檔案覆寫確認防呆(Destination File Overwrite Check)
- 判斷
file2是否已存在。若不存在,直接略過此迴圈;若已存在,進入while迴圈詢問使用者是否覆寫("The file existed, Overwrite it? y/n? ")。 - 若使用者輸入
'n'或'N',則提示重新輸入另一個目的檔名,並由迴圈重新檢查新檔名是否衝突。 - 若使用者輸入其他字元(包含
'y'、'Y'或任意非 N 字元),則執行else: break跳出迴圈,代表確定使用該檔名(允許覆寫)。
- 第四階段:執行複製與關閉檔案
- 以唯讀模式開啟
file1,以寫入模式開啟file2。 - 將
file1的所有文字內容讀出後存入變數content,接著寫入file2。 - 依序關閉兩檔案物件,完成檔案複製作業。
選項分析
本題為非選擇題(程式功能問答題),以下針對各程式碼邏輯區塊進行逐段功能與狀態轉換解析:
- 區塊一:模組匯入與初次輸入
import os.path
file1 = input("Input a file name: ")
file2 = input("Input the other file name: ")
os.path提供了與作業系統路徑相關的實用工具。- 透過
input取得使用者鍵入的字串,分別代表欲讀取的來源檔名與欲寫入的目的檔名。
第 三 題20 分
請撰寫一支密碼產生模組程式。此模組的密碼組成為一個五位數字,最後一碼(個位數)為驗證碼。合法的密碼規則是:除了驗證碼之外的所有數字相乘後,再除以 10 的餘數當作驗證碼。
例如: 即為合法的密碼,因為 。
請撰寫一支完整 C/C++ 程式,包含 main() 與 codeGen():
codeGen()的功能為:輸入參數為密碼的前四碼,輸出為產生驗證碼後的五位數字密碼。- 程式讓使用者輸入密碼的前四碼後,檢查使用者所輸入的數值是否為四位數。
- 若輸入正確,則呼叫
codeGen(),將傳回的五位數字密碼從螢幕顯示出。 main()需有迴圈功能,詢問使用者是否要繼續輸入,直到使用者按下不是Y或y鍵時結束程式。(20 分)
登入後即可作答並保存紀錄。
核心觀念
本題為典型的模組化程式設計與字元/數值處理題,評量考生在 C/C++ 語言中的基礎程式架構與流程控制能力,核心要點涵蓋:
- 函式模組化設計(Modular Programming):包含函式原型宣告(Declaration)、定義(Definition)以及參數傳遞(Parameter Passing)與回傳值(Return Value)。
- 整數除法與餘數運算(Integer Division & Modulo Operations):利用除法運算子
/(商數)與取餘數運算子%分離出整數的各個獨立位數。 - 資料驗證與範圍檢查(Data Validation):判斷數值是否符合題意之「四位數」(即介於 至 之間)。
- 迴圈控制與 I/O 緩衝區管理(Loop Control & Buffer Handling):採用後測試迴圈(
do-while)確保至少執行一次互動,並正確處理字元讀取時殘留於標準輸入串流中的換行字元(\n)。
解題方法
本題解題步驟分為兩大主軸:codeGen 模組的運算邏輯推導,以及 main 函式的互動與驗證流程。
1. 密碼產生模組 codeGen 之推導
設輸入之前四碼為正整數 ():
- 分離位數:
- 千位數:
- 百位數:
- 十位數:
- 個位數:
- 計算乘積與驗證碼: 各個位數乘積 。 驗證碼(個位數)
- 組合五位數密碼: 將原四位數左移一位(乘以 10)後加上驗證碼 : 回傳該整數值即為題目所需之五位數密碼。
2. 主程式 main 之流程規劃
- 輸入驗證:讀取使用者輸入後,檢查是否符合條件 。若不符合,輸出提示訊息並跳過運算;若符合,呼叫
codeGen(N)並輸出結果。 - 持續執行迴圈:使用
do-while結構,於每次運算結束後詢問使用者是否繼續。使用者輸入之字元若為'Y'或'y'則進入下一次反覆,否則結束迴圈。
解題技巧與常見陷阱
scanf讀取字元時的緩衝區換行陷阱(關鍵得分點): 在輸入整數後按下 Enter 鍵,換行字元\n會留在標準輸入緩衝區內。若後續直接使用scanf("%c", &choice);,會直接讀到該換行字元而導致迴圈非預期結束。
第 四 題25 分
請撰寫一支完整的 C/C++ 程式,此程式包含一維陣列。陣列元素的個數由使用者輸入,陣列元素值由時間亂數產生,數值範圍介於 (含)至 (含)間。
此程式需包含下列函數:
(一)arrMean():將所傳入的一維陣列計算其陣列元素的平均值後傳回。(10 分)
(二)arrBubble():將所傳入的一維陣列利用氣泡排序法,將陣列元素由小至大排序。(10 分)
(三)撰寫 main(),以驗證 arrMean() 與 arrBubble() 的正確性。(5 分)
登入後即可作答並保存紀錄。
核心觀念
本題為經典的 C/C++ 基礎綜合實作題,主要評量考生對記憶體管理、亂數生成、陣列傳遞與基礎演算法的掌握度:
- 動態記憶體配置(Dynamic Memory Allocation):
題目要求「陣列元素個數由使用者輸入」,在 C/C++ 中靜態陣列大小必須為編譯期常數(Compile-time Constant)。因此應使用動態配置(如 C 的
malloc/free或 C++ 的new[]/delete[]),以確保程式的可移植性與標準相容性。 - 時間亂數生成(PRNG Seeding & Mapping):
透過
<time.h>的time(NULL)做為種子(Seed)傳入srand初始化偽亂數產生器;利用取餘數運算將rand的輸出範圍映射至區間 : 本題範圍為 至 ,公式即為rand % 99 + 1。 - 陣列的函式傳遞(Array Decay to Pointer):
一維陣列傳遞給函式時會退化為指向其首元素的指標(
int *或int[])。在 C/C++ 中無法由指標直接得知陣列大小,因此必須同時將元素個數 作為參數傳入。 - 數值型別轉換與平均值計算: 整數陣列的元素總和可能造成溢位(Overflow),且平均值為浮點數,進行除法時需做顯式型別轉換(Explicit Type Casting),避免整數除法產生截斷誤差(Truncation Error)。
- 氣泡排序法(Bubble Sort): 相鄰元素兩兩比較,若前大於後則交換,每輪走訪將當前最大值推移至末端。其時間複雜度在最差與平均情況下皆為 。
解題方法
(一)arrMean 函式設計
- 參數與回傳值:傳入陣列首位址
const int arr[](使用const確保唯讀安全)與長度int n,回傳值型別定為double。 - 計算推導:
- 累加變數
sum使用long long或double型別,避免當陣列規模較大時整數溢位: - 在除法運算時確保被除數或除數轉為浮點數:
(double)sum / n。 - 若 ,應回傳 作為邊界防護。
(二)arrBubble 函式設計
- 參數與傳址機制:傳入
int arr[]與長度int n。陣列在 C/C++ 預設透過位址傳遞,函式內對陣列元素的交換會直接反映至原陣列。 - 演算法實作:
- 外層迴圈控制回合數(共需 回合):
for (int i = 0; i < n - 1; i++)。 - 內層迴圈進行相鄰元素比較:
for (int j = 0; j < n - 1 - i; j++)。 - 若
arr[j] > arr[j + 1]則進行數值交換(Swap)。 - 可加入旗標(Flag)優化:若某一回合未發生任何交換,代表已完成排序,可提早終止。
(三)main 驗證流程設計
- 輸入與檢查:讀取使用者輸入的個數 ,並檢驗 。
- 記憶體配置:配置 個整數空間。
- 亂數初始化與填值:呼叫
srand((unsigned int)time(NULL)),利用迴圈填入 的亂數值,並輸出原始陣列。 - 驗證與輸出:
- 呼叫
arrMean,印出計算結果(格式化至小數點後兩位)。 - 呼叫
arrBubble,印出排序後的陣列,直觀驗證是否由小至大排列。
- 釋放記憶體:執行
free避免記憶體洩漏(Memory Leak)。
子題評分要點分析
- (一)
arrMean(10 分): 重點在於函式原型定義是否精確、迴圈累加是否完整、回傳型別是否採用浮點數(float或double),以及是否避免了整數除法的整除陷阱。 - (二)
arrBubble(10 分): 重點在於兩層迴圈的邊界條件是否正確(尤其是內層終止條件n - 1 - i)、相鄰交換邏輯(三步驟暫存變數交換法)是否無誤。 - (三)
main驗證(5 分): 重點在於是否包含「輸入個數」、「時間亂數種子設定」、「產生 亂數」、「正確呼叫上述二函式」並「完整印出結果」以達成題目要求的驗證目的。
解題技巧與常見陷阱
第 五 題25 分
使用 C++、Java 或 Python 程式語言設計機車里程數計算程式:
(一)motor:機車類別
brand:機車品牌的私有字串資料項目。fuel:機車油量(公升)的私有數值資料項目。speed:機車速度(公里/小時)的私有數值資料項目。km:機車可行駛公里數的私有數值資料項目。- 建構函數可將新建立物件之機車品牌、油量、速度作初始化。
calKM()公有方法計算里程數,依標準機車計算,平均每公升可跑 15 公里。show()公有方法從螢幕顯示出機車品牌、油量、速度、可行駛公里數資訊。
(二)electricMotor:電動機車類別
- 繼承機車(
motor)類別。 seat:電動機車座位數私有數值資料項目。- 建構函數可將新建立物件初始化。
calKM()公有方法計算電動機車可行駛公里數,不受速度影響,電動機車平均每公升可跑 20 公里。show()公有方法從螢幕顯示出電動機車品牌、油量、速度、可行駛公里數資訊。
(三)raceMotor:競技機車類別
- 繼承機車(
motor)類別。 type:競技機車型號之私有字串資料項目。- 建構函數可將新建立物件初始化。
calKM()公有方法計算競技機車可行駛公里數:競技機車若時速超過每小時 60 公里,則平均每公升可跑 10 公里;沒超過的話則平均每公升可跑 12 公里。show()公有方法從螢幕顯示出競技機車品牌、油量、速度、可行駛公里數資訊。
此題不需讓使用者輸入相關數值,只需在程式內建立電動機車與競技機車物件時給予相關的數值,但程式需執行 show() 方法以驗證程式的正確性。(25 分)
登入後即可作答並保存紀錄。
核心觀念
本題為標準的物件導向程式設計(Object-Oriented Programming, OOP)實作題,評量重點涵蓋以下核心概念:
- 封裝(Encapsulation)與存取控制(Access Control):
- 題目明確要求各成員屬性為「私有」(
private)。依封裝原則,子類別無法直接存取父類別的私有成員,必須透過父類別提供的公有(public)或保護(protected)存取方法(Getter / Setter)進行資料操作。
- 繼承(Inheritance)與建構子鏈(Constructor Chaining):
- 子類別使用
extends繼承父類別,並在其建構函數中使用super(...)呼叫父類別建構函數,完成基礎資料項目的初始化。
- 多型與方法覆寫(Method Overriding):
- 子類別依個別行駛邏輯重新定義父類別的
calKM與show方法,展現多型行為。
- 里程數計算模型:
- 一般機車:
- 電動機車:
- 競技機車:
解題方法
本題選用國家考試中最受閱卷委員青睞、型別定義嚴謹的 Java 程式語言 進行實作:
- 父類別
motor設計:
- 將
brand、fuel、speed、km宣告為private。 - 實作三參數建構子初始化
brand、fuel、speed,並將初始里程km設為 。 - 提供
getFuel、getSpeed與setKM、getKM等方法,供子類別在不破壞封裝的前提下讀取與更新狀態。 - 實作公有方法
calKM與show。
- 衍生類別
electricMotor設計:
- 宣告私有屬性
seat。 - 建構子接收四個參數,前三個透過
super(brand, fuel, speed)傳遞給父類別,最後初始化this.seat。 - 覆寫(
@Override)calKM:呼叫setKM(getFuel * 20)。 - 覆寫
show:可呼叫super.show顯示基礎資訊,並附加顯示座位數seat。
- 衍生類別
raceMotor設計:
- 宣告私有屬性
type。 - 建構子透過
super(brand, fuel, speed)及this.type完成初始化。 - 覆寫
calKM:利用if (getSpeed > 60)判斷油耗係數並計算設定km。 - 覆寫
show:顯示基礎資訊並可附加顯示型號type。
- 主程式驗證:
- 建立
electricMotor與raceMotor物件並傳入指定初始值。 - 呼叫各物件之
calKM計算里程數後,執行show印出結果,驗證多型與覆寫之正確性。
選項分析(規格細部檢核)
本題為程式設計題,依據題目各項規格逐一檢驗實作切入點:
- (一)
motor類別: brand(字串)、fuel(數值)、speed(數值)、km(數值)全數設為private,數值型別採double避免整數除法失真。- 建構函數接收 3 個參數,符合「初始化機車品牌、油量、速度」要求。
calKM實作每公升 15 公里之運算;show格式化輸出各項資料。- (二)
electricMotor類別: - 正確繼承
motor,並擴充私有成員seat。 - 建構函數完整轉送基礎欄位至父類別。
calKM依每公升 20 公里重新計算,忽略速度影響。- (三)
raceMotor類別: - 正確繼承
motor,並擴充私有成員type。 calKM具備條件分支判斷(時速 為 ,否則為 )。- 驗證程式(
main方法): - 依照題目要求,不使用
Scanner讀取鍵盤輸入,直接硬編碼(Hardcode)測試資料建立物件。 - 明確呼叫
calKM與show達成題目要求之「驗證程式的正確性」。
解題技巧與常見陷阱
- 封裝性陷阱(最關鍵扣分點):
- 許多考生在子類別中直接寫
this.fuel * 20或km = ...,在 Java 與 C++ 中會直接引發編譯錯誤(Compiler Error),因為父類別欄位宣告為private。 - 正確做法:務必在父類別建立
protected或public的 Getter 與 Setter,或者宣告protected存取級別;但題目已指定父類別為「私有」,故撰寫 Getter/Setter 是最正統且不失分的 OOP 作法。
- 數值型態的選擇:
- 油量、時速與里程數多含小數點,宜使用倍精度浮點數
double,避免使用int造成截尾誤差。
super的調用位置:
- 子類別建構子內若顯式呼叫父類別建構子
super(...),該陳述式必須是建構子內的第一行程式碼。