111 高普考高考三級 資訊處理 程式設計 考古題詳解

111 年・高普考・高考三級・資訊處理
試題代碼 程式設計

第 一、 題20 分

請問以下三小題 C 程式執行的結果為何?請注意須說明答案是如何產生的,否則不給分。

(一)(5 分)

#include <stdio.h> #include <stdlib.h>

int main(void) { int x; float y;

for (x=0, y=50; x<25; x+=5, y/=2)
    printf("x=%d, y=%4.2f\n", x, y);

return 0;

}

(二)(5 分)

#include <stdio.h> #include <stdlib.h>

int a=10, fun(int);

int main(void) { int b=6;

printf("a=%d, b=%d, fun(a)=%d\n", a, b, fun(a));

return 0;

}

int fun(int b) { a-=5; b/=2; return(a+b); }

(三)(10 分)

#include <stdio.h> #include <stdlib.h>

#define SIZE 10

void fun(int *, int);

int main(void) { int x[SIZE] = {1,2,3,4,5,6,7,8,9,10};

fun(x, SIZE);
printf("\n");

return 0;

}

void fun(int a, int size) { if (size > 0) { fun(a+3, size-3); printf("(a+%d)=%d\n", SIZE-size, *a); } }

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

  1. for 迴圈的多重運算式控制:在 for 的初始化與迭代步進區塊中,使用逗號運算子(Comma Operator ,)可同時對多個變數進行賦值與更新。
  2. 格式化輸出(printf):
  • %d:以十進位整數格式輸出。
  • %4.2f:浮點數格式化輸出,其中小數點後保留 22 位,總欄位寬度至少為 44。當數值總長度(含整數、小數點及小數位數)大於等於寬度規範時,系統依實際長度完整顯示,不予截斷。
  1. 終止條件判斷:每次迴圈本體執行完畢後,執行步進運算式,再判定條件式是否成立,決定是否繼續執行。

解題方法

初始狀態:x=0x = 0(整數),y=50.0y = 50.0(單精度浮點數)。 每次迴圈結束後執行更新運算:x←x+5x \leftarrow x + 5,y←y/2y \leftarrow y / 2。

執行追蹤(Trace Table):

迴圈次數條件檢查(x<25x < 25)執行輸出(printf("x=%d, y=%4.2f\n", x, y);)步進更新(x+=5, y/=2x \mathrel{+}= 5,\ y /= 2)
第 1 次0<250 < 25(成立)x=0, y=50.00x=5, y=25.0x = 5,\ y = 25.0
第 2 次5<255 < 25(成立)x=5, y=25.00x=10, y=12.5x = 10,\ y = 12.5
第 3 次10<2510 < 25(成立)x=10, y=12.50x=15, y=6.25x = 15,\ y = 6.25
第 4 次15<2515 < 25(成立)x=15, y=6.25x=20, y=3.125x = 20,\ y = 3.125
第 5 次20<2520 < 25(成立)x=20, y=3.13(或 3.12)x=25, y=1.5625x = 25,\ y = 1.5625
第 6 次25<2525 < 25(不成立)終止迴圈,跳出結束

解題技巧與常見陷阱

  • 欄位寬度與位數:%4.2f 的寬度 44 包含整數部、小數點與 22 位小數。例如 50.0050.00 總長度為 55 個字元,超過設定寬度 44,因此輸出不會補空格,直接輸出 50.00。
  • 浮點數捨入規則:當 y=3.125y = 3.125 時,依一般數學四捨五入輸出為 3.13;若依部分符合 IEEE 754 規範之編譯器(採偶數捨入法 / Banker's Rounding),因前一位為偶數 22,亦可能輸出為 3.12。國考閱卷時此兩種捨入值皆屬標準給分範圍。
  • 終止邊界:判斷式為 x<25x < 25(不含等號),因此 x=25x = 25 時不會進入迴圈本體。

【答案】

x=0, y=50.00
x=5, y=25.00
x=10, y=12.50
x=15, y=6.25
x=20, y=3.13

(註:最後一行之 y 依編譯器捨入模式亦可為 3.12)


(二)

核心觀念

  1. 變數有效範圍(Scope)與遮蔽(Shadowing):
  • 檔案層級宣告的變數為全域變數(Global Variable),在程式各函式中皆可存取。
  • 區域變數(Local Variable)與函式參數的有效範圍僅限於宣告所在的區塊,若與全域變數同名,會遮蔽全域變數。
  1. 傳值呼叫(Call by Value):C 語言之引數傳遞皆為傳值呼叫。函式內的參數為獨立記憶體空間的複本,對其運算不影響呼叫端的原始變數。
  2. 副作用(Side Effect)與引數評估順序(Order of Evaluation):
  • 在 ISO C 標準中,函式呼叫時引數的計算順序屬於「未指定行為」(Unspecified Behavior)。
  • 主流編譯器(如 GCC、Clang、MSVC 於 x86/x64 環境下之 cdecl 呼叫慣例)通常採「由右至左」(Right-to-Left)順序評估引數。

解題方法

  1. 變數識別:
  • 全域變數:int a = 10;
  • main 函式區域變數:int b = 6;
  1. 函式 fun(int b) 執行推導:
  • 呼叫 fun(a) 時,傳入當時全域變數的值 1010。
  • 函式參數 b 接收到 1010(與 main 內的 b 毫無關聯)。
  • a -= 5;:修改全域變數 aa,使全域變數 a=10−5=5a = 10 - 5 = 5。
  • b /= 2;:修改參數 b,使參數 b=10/2=5b = 10 / 2 = 5。
  • return(a+b);:回傳 5+5=105 + 5 = 10。
  1. printf("a=%d, b=%d, fun(a)=%d\n", a, b, fun(a)); 之引數求值分析:
  • 情況一:主流編譯器慣例(由右至左評估)
  1. 先求值最右側引數 fun(a):傳入 a=10a=10,全域變數 aa 被修改為 55,函式回傳 1010。
  2. 接著求值中間引數 b:取 main 區域變數 b=6b = 6。
  3. 最後求值最左側引數 a:取全域變數 aa,此時已被 fun 修改為 55。
  4. 輸出結果為:a=5, b=6, fun(a)=10。
  • 情況二:由左至右評估
🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 二、 題20 分

資料庫是企業組織或政府部門中用以保存大量資料的機制。下圖為資料表的結構,請回答以下各小題。(每小題 10 分,共 20 分)

🖼️【此處有附圖,請對照原卷】

資料表結構如下:

employee:

  • id:varchar(10)
  • first_name:varchar(30)
  • last_name:varchar(20)

salary_slip:

  • id:varchar(10)
  • year:int
  • month:int
  • amount:int

employee 與 salary_slip 的關係為一對多,即一位 employee 可對應多筆 salary_slip。

(一)請以 SQL 列出某一個人的年度薪資總額,必須顯示 id、first_name、last_name 及總額。

(二)現在的資料查詢服務常見於網頁系統,而 SQL Injection 是最常見的資料庫攻擊方式。請問下列查詢語句是否會有被攻擊的疑慮?若有的話該如何改善?程式碼可以使用 PHP 或 ASP.NET。

SELECT first_name, last_name FROM employee WHERE id='A001'

🖼️ 本題原卷含圖表。基於試題來源之版權考量,本站不轉載原卷影像; 題目文字已完整轉錄,圖表請自行參閱考選部公告之試題原檔。

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念: salary_slip 每筆資料代表一筆薪資紀錄;要計算年度總額,需依員工與年度篩選資料,再以 SUM(amount) 加總。因題目未指定年度,以下以 :year 作為年度參數、:id 作為員工編號參數。

解題方法: 以 employee.id = salary_slip.id 連結兩表,再依員工編號篩選並分組。使用 LEFT JOIN 可保留沒有該年度薪資紀錄的員工,並以 COALESCE 將加總結果顯示為 0。

SELECT e.id,
 e.first_name,
 e.last_name,
 COALESCE(SUM(s.amount), 0) AS annual_total
FROM employee AS e
LEFT JOIN salary_slip AS s
 ON s.id = e.id
 AND s.year = :year
WHERE e.id = :id
GROUP BY e.id, e.first_name, e.last_name;

解題技巧: 年度條件應放在 LEFT JOIN 的 ON 子句中;若放在 WHERE 子句,沒有薪資紀錄的員工會被排除,效果會近似 INNER JOIN。

(二)SQL Injection 判斷與改善

核心觀念: SQL Injection 是將使用者輸入直接拼接進 SQL 指令,使輸入內容被當成 SQL 語法執行。使用參數化查詢可將輸入值與 SQL 指令分開處理。

題目中的查詢為:

🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 三、 題30 分

請使用 C、C++、Java 或 Python 程式語言撰寫採用五位數整數來進行資料加密的完整程式。(30 分)

  1. 撰寫加密函數 encrypt(),此函數可將所傳入的五位數整數進行加密,並將加密後的密碼傳回。加密的規則如下:
  • 先將該五位數整數的每位數值分別以「加 5 後除以 10 之餘數」取代。
  • 再將取代後之數字的第一位數與第五位數互換,第二位數與第四位數互換,第三位數不變,最後取得一個新整數,此即為加密後的密碼。(註:第一位數為萬分位、第二位數為千分位,以此類推。)
  1. 撰寫解密函數 decipher(),此函數可將所傳入的五位數密碼進行解密,並將解密後的整數傳回。解密的規則是將上述加密後之密碼還原為原傳入的整數。

  2. 撰寫主程式來驗證上述之加密與解密函數的正確性。程式一開始先讓使用者輸入任一之五位數整數[不在合理範圍內(10000~99999)須請使用者重新輸入],在呼叫加密函數後將所傳回之密碼從螢幕上顯示出;再將該密碼傳入解密函數,再將所傳回之整數從螢幕上顯示出。程式須可讓使用者持續輸入五位數之整數,直到使用者輸入 0(整數)時結束程式的執行。

以下為程式執行的範例:(備註:斜體加外框線之整數為使用者所輸入,其餘皆為程式執行的輸出。)

請輸入一個五位數的整數(輸入 0 結束程式):1234 所輸入的數值並不是五位數之整數 請重新輸入:12345 加密後的密碼為:09876 解密後的密碼為:12345 請輸入一個五位數的整數(輸入 0 結束程式):67890 加密後的密碼為:54321 解密後的密碼為:67890 請輸入一個五位數的整數(輸入 0 結束程式):0 感謝使用此程式,歡迎您對此程式的優化提出建議。

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題為民國 111 年公務人員高等考試三級考試(資訊處理類科)「程式設計」之經典非選擇題(佔 30 分),旨在評量考生對於模組化程式設計、同餘算術運算、位數處理及互動式輸入防呆控制之掌握程度。核心概念涵蓋:

  1. 位數分解與數值重組(Digit Extraction & Reconstruction):
  • 透過整數除法(/ 或 //)與取模數運算(%),逐位分離五位數整數之萬分位(第 1 位)、千分位(第 2 位)、百分位(第 3 位)、十分位(第 4 位)與個位(第 5 位)。
  • 運算完成後,再按十進位權重(104,103,102,101,10010^4, 10^3, 10^2, 10^1, 10^0)相乘並加總,組裝回單一整數。
  1. 同餘代換的可逆性(Invertibility of Modular Arithmetic):
  • 加密替換公式為: ei=(di+5) mod 10e_i = (d_i + 5) \bmod 10
  • 由於在模數 10 下,加 5 的加法反元素(Additive Inverse)為 −5≡+5(mod10)-5 \equiv +5 \pmod{10},因此解密公式可直接寫為: di=(ei+5) mod 10d_i = (e_i + 5) \bmod 10 這說明在模數 10 的環境下,此位數代換運算本身具備自反性(Involutory Property)。
  1. 前導零格式化輸出(Formatting with Leading Zeros):
  • 題目範例中,原數 12345 加密後為 09876。當密碼第一位數(萬分位)為 00 時,以整數形態傳回之數值為 98769876。
  • 在螢幕輸出時,必須指定五位數且不足補零的格式(例如 C 語言的 %05d 或 Python 的 {:05d}),方能符合題目要求的顯示外觀。
  1. 防呆驗證與旗標值迴圈控制(Sentinel-Controlled Loop & Validation):
  • 程式採用旗標值(Sentinel Value)0 作為結束訊號。
  • 非 0 且不在 [10000,99999][10000, 99999] 區間之整數視為無效輸入,須以巢狀迴圈進行重新輸入之提示與校驗。

解題方法

本題依題意分為三個部分循序推導與實作:

1. 加密函數 encrypt 演算法推導

設傳入之五位數整數為 NN(滿足 10000≤N≤9999910000 \le N \le 99999):

  1. 位數萃取: d1=⌊N/10000⌋ mod 10,d2=⌊N/1000⌋ mod 10,d3=⌊N/100⌋ mod 10d_1 = \lfloor N / 10000 \rfloor \bmod 10, \quad d_2 = \lfloor N / 1000 \rfloor \bmod 10, \quad d_3 = \lfloor N / 100 \rfloor \bmod 10 d4=⌊N/10⌋ mod 10,d5=N mod 10d_4 = \lfloor N / 10 \rfloor \bmod 10, \quad d_5 = N \bmod 10
  2. 位數取代: ei=(di+5) mod 10(i=1,2,3,4,5)e_i = (d_i + 5) \bmod 10 \quad (i = 1, 2, 3, 4, 5)
  3. 位置互換:
  • 第 1 位與第 5 位互換:c1=e5,c5=e1c_1 = e_5, c_5 = e_1
  • 第 2 位與第 4 位互換:c2=e4,c4=e2c_2 = e_4, c_4 = e_2
  • 第 3 位不變:c3=e3c_3 = e_3
  1. 數值重組: 傳回新整數: C=c1×104+c2×103+c3×102+c4×101+c5C = c_1 \times 10^4 + c_2 \times 10^3 + c_3 \times 10^2 + c_4 \times 10^1 + c_5

2. 解密函數 decipher 演算法推導

設傳入之五位數密碼為 CC:

  1. 位數萃取: 若 c1=0c_1 = 0(例如 C=9876C = 9876),⌊9876/10000⌋=0\lfloor 9876 / 10000 \rfloor = 0,依然能精確萃取出 c1=0,c2=9,c3=8,c4=7,c5=6c_1 = 0, c_2 = 9, c_3 = 8, c_4 = 7, c_5 = 6。
  2. 位置還原:
  • 互換第 1 位與第 5 位:e1=c5,e5=c1e_1 = c_5, e_5 = c_1
  • 互換第 2 位與第 4 位:e2=c4,e4=c2e_2 = c_4, e_4 = c_2
  • 第 3 位不變:e3=c3e_3 = c_3
  1. 位數代換還原: di=(ei+5) mod 10(i=1,2,3,4,5)d_i = (e_i + 5) \bmod 10 \quad (i = 1, 2, 3, 4, 5)
  2. 數值重組: 傳回還原後之原整數: N=d1×104+d2×103+d3×102+d4×101+d5N = d_1 \times 10^4 + d_2 \times 10^3 + d_3 \times 10^2 + d_4 \times 10^1 + d_5

3. 主程式流程控制

  • 外層使用無窮迴圈 while (1) 持續要求使用者輸入。
  • 若輸入值為 0,印出感謝訊息後立即跳出迴圈並終止程式。
  • 若輸入值小於 10000 或大於 99999,進入防呆驗證迴圈:印出「所輸入的數值並不是五位數之整數」及「請重新輸入:」,直到輸入合法五位數;若在重新輸入時使用者輸入 0,亦能正確終止程式。
  • 輸入有效後,依序呼叫 encrypt 與 decipher,並按題目格式要求輸出結果。

選項分析

本題為非選擇題(程式設計申論與實作題,總分 30 分)。依據國家考試評分要點,本題三大子題的評分標準與檢驗要點分析如下:

  • 子題 1:加密函數 encrypt(配分約 10 分)
  • 核心檢驗:函式介面須為接收整數並回傳整數。能否正確處理陣列或位數的萃取、加 5 取模數,以及第 1/5 位、第 2/4 位的交換順序。
  • 常見扣分點:將整數直接當作字串處理而未符合傳入/傳回「整數」之要求;或位數交換時覆蓋原本變數值而未保留暫存變數。
  • 子題 2:解密函數 decipher(配分約 10 分)
  • 核心檢驗:能否精準執行逆運算。逆運算之順序必須與加密時相反(先換回位置,再進行數值反向代換;或先代換再換回位置,數學上兩者皆可,但位置對調不可遺漏)。
  • 常見扣分點:當加密後首位為 0(整數僅剩四位數)時,若未考慮除以 10000 得到 0 的特徵,導致解密陣列長度錯置。
  • 子題 3:主程式驗證與輸入防呆(配分約 10 分)
  • 核心檢驗:迴圈控制架構是否能持續執行至使用者輸入 0 為止;輸入值範圍檢驗(10000∼9999910000 \sim 99999)是否確實;終止訊息與重新輸入字串是否百分之百符合題目範例。
  • 常見扣分點:漏寫邊界條件判斷、遇到非五位數直接結束程式而未給予重新輸入機會、未將首位為 0 之密碼以 5 位數補零格式(%05d)印出。

解題技巧

  1. 同餘加減速算竅門: 在十進位系統中,若代換規則為 +k(mod10)+k \pmod{10},其還原為 −k≡(10−k)(mod10)-k \equiv (10 - k) \pmod{10}。本題 k=5k = 5,10−5=510 - 5 = 5,因此加密與解密的位數取代算式完全相同,皆為 (x + 5) % 10,解密時不必額外寫條件判斷式防止負數。
  2. 前導零的陷阱(The Leading Zero Trap): 密碼傳回值為 int,電腦在儲存整數時不會保留左側無意義的零(0987609876 會存為 98769876)。顯示時務必使用 %05d(C/C++)或 f"{c:05d}"(Python),強制以五位數寬度並於左側補零輸出。
  3. 驗算檢查法:
🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

第 四、 題30 分

抽象(abstract)類別、介面(interface)、覆寫(override)方法、多載(overload)方法是物件導向程式設計實現多型(polymorphism)的方式。下圖是人事系統中人員基本資料維護的類別圖,請說明類別圖中的覆寫方法及多載方法名稱(須說明理由),並使用 C++、Java 或 Python 程式語言撰寫 Person 類別與 Police 類別的程式碼。Police 類別之 GetPersonalInformation 函數必須傳回身分證(id_no)、姓名(name)、職稱(rank),UpdateRoleTitle 函數必須完整作更新 police_rank。(30 分)

🖼️【此處有附圖,請對照原卷】

類別圖內容如下:

  • Program

    • Main(string[] args):void
  • Person <<abstract>>

    • id_no:string

    • name:string

      • GetPersonalInformation():string
      • UpdateRoleTitle():void
  • Police

      • police_rank:PoliceRank
      • Police(id:string, name:string)
      • GetPersonalInformation():string
      • UpdateRoleTitle(title:?):void
  • Staff

      • staff_position:StaffPosition
      • Staff(id:string, name:string)
      • GetPersonalInformation():string
      • UpdateRoleTitle(title:?):void
  • PoliceRank

      • code:string
      • rank:string
      • PoliceRank(code:string, rank:string)
  • StaffPosition

      • code:string
      • title:string
      • StaffPosition(code:string, title:string)
🖼️ 本題原卷含圖表。基於試題來源之版權考量,本站不轉載原卷影像; 題目文字已完整轉錄,圖表請自行參閱考選部公告之試題原檔。

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查物件導向中的覆寫與多載:

  • 覆寫(override):子類別重新定義父類別的方法,方法名稱、參數列與回傳型別須相符。透過父類別參考呼叫時,可依實際物件型別執行子類別版本。
  • 多載(overload):同一類別或繼承關係中,方法名稱相同,但參數列不同。編譯器依呼叫時提供的參數決定要執行哪個版本。
  • 抽象類別可以包含已實作的方法,也可以包含抽象方法;題圖標示 Person 為抽象類別,並未將每個方法都標示為抽象方法。

解題方法

比對 Person 與子類別中的方法簽章:

  1. Person.GetPersonalInformation 與 Police.GetPersonalInformation 名稱、參數列及回傳型別均相同,因此 Police.GetPersonalInformation 是覆寫。
  2. Person.UpdateRoleTitle 沒有參數,Police.UpdateRoleTitle(title: ?) 有一個參數。兩者名稱相同、參數列不同,因此是多載,不是覆寫。
  3. 圖中 title 的型別未標明。由 Police 的欄位 police_rank : PoliceRank 可知,合理假設參數型別為 PoliceRank;更新時將整個物件指定給 police_rank,才能同時更新職稱代碼與職稱名稱。

程式碼(C++)

以下將 Person 保持為抽象類別,並依圖示保留無參數的 UpdateRoleTitle;有參數版本則負責完整更新警察職稱。題圖沒有交代無參數版本的實際更新規則,因此基底類別僅保留其方法介面。

🔒

後續完整解題步驟與【答案】

免費註冊,享 3 天全站完整詳解閱覽。

免費註冊

其他考古題