112 地方特考三等 資訊處理類科 程式設計 考古題詳解
第 一 題25 分
關於下列 C 程式碼,請說明程式執行後,程式碼編號 27~33 的輸出,以及其運算邏輯。
#include <stdio.h> #define SIZE 30
typedef enum direction { North, South, East=3, West } dir_t;
int f1(int a, int b) { int x = 3.0 / a; double y = (a/2) * (b%3) + x; return y; }
int f2(dir_t d) { d = (North+East)/2 > d ? East : West; return d; }
int f3(int a, int b) { if (b==a || b<=1) return a+b; else if (a<=1) return b-a; else return f3(a-b, a-1)+b+a; }
int f4(int a, int b) { int data[SIZE]; for (int i=1, k=0; i<a; i++) { if (i%2==0) data[k++]=i; } return data[b]; }
unsigned int f5(unsigned int a, unsigned int b) { return (~a&b); }
int main() { printf("%d\n", f1(10, 4)); printf("%d\n", f2(South)); printf("%d\n", f3(6, 4)); printf("%u\n", f3(7, 4)); printf("%d\n", f4(20, 5)); printf("%d\n", f4(10, 4)); printf("%u\n", f5(4, 7)); return 0; }
登入後即可作答並保存紀錄。
核心觀念
本題考查 C 語言的整數除法與型別轉換、列舉常數、遞迴、陣列索引,以及位元補數與位元運算。輸出依 main 中的呼叫順序,分別對應程式碼編號 27~33。
解題方法
- 程式碼編號 27:
f1(10, 4)
a、b、x 都是 int。因此 3.0 / a 先以浮點數計算為 ,再轉成 int,小數部分截去,故 x=0。
在 (a/2) 中兩個運算元都是整數,因此 ;而 。所以:
return y 將 double 轉成 int,結果是 5。輸出:5。
- 程式碼編號 28:
f2(South)
列舉值依宣告順序為:
因此 (North+East)/2 是 。條件 1 > d 對 d=South=1 不成立,故選擇 West,回傳 4。輸出:4。
- 程式碼編號 29:
f3(6, 4)
遞迴規則是:若 b==a 或 b<=1,回傳 a+b;否則若 a<=1,回傳 b-a;其餘回傳 f3(a-b, a-1)+b+a。
第二層呼叫 f3(-3,1) 因 b<=1,直接回傳 。輸出:15。
- 程式碼編號 30:
f3(7, 4)
在 f3(-3,2) 中,b==a 與 b<=1 均不成立,但 a<=1 成立,因此回傳 。
第 二 題25 分
針對下列 C++ 程式,請標示出 Except 類別的 f1、⋯、f6 函式中有問題的函式,並說明其問題之原因;並請說明若將有問題的函式和程式碼刪除,其程式執行後之輸出。
#include <stdexcept> #include <iostream> #include <string> using namespace std;
class Except { public: void f1(int c); void f2(); void f3(); void f4(); void f5(); void f6(); };
int main() { Except e; e.f1(1); e.f2(); e.f3(); e.f4(); e.f5(); e.f6(); return 0; }
void Except::f1(int c) { if (c<0) throw out_of_range("large"); cout<<"exc1"<<endl; }
void Except::f2() { f1(-1); }
void Except::f3() { try { f1(-1); cout<<"ok"<<endl; } catch(exception &e) { cout<<"exc2"<<endl; } }
void Except::f4() { try { throw out_of_range("no"); } catch(out_of_range &e) { cout<<e.what()<<endl; cout<<"exc3"<<endl; } }
void Except::f5() { try { throw out_of_range("yes"); } catch(exception &e) { cout<<"exc41"<<endl; } catch(out_of_range &e) { cout<<e.what()<<endl; cout<<"exc42"<<endl; } }
void Except::f6() { try { throw out_of_range("ok"); } finally { cout<<"exc6"<<endl; } }
登入後即可作答並保存紀錄。
核心觀念
本題考 C++ 例外處理的基本規則:
throw會將例外往呼叫堆疊外層傳遞,直到找到可處理該例外型別的catch。若離開main時仍無人處理,程式會呼叫std::terminate,不會繼續執行後續函式。std::out_of_range繼承自std::exception,因此catch(exception&)可以捕捉out_of_range。- 同一組
catch子句要由較具體的型別排在較一般的型別之前;否則一般型別先捕捉後,後面的具體型別就無法接手。 - C++ 沒有
finally語法。這種語法常見於其他語言,不能直接用在 C++ 的try後面。
解題方法
逐一追蹤每個函式中的例外是否有相應的 catch,並確認例外是否能離開函式、一路傳到 main。若某函式有問題,依題意刪除該函式的定義及呼叫,再按剩餘呼叫順序列出輸出。
各函式判斷
f1:沒有問題
當 c < 0 時,執行 throw out_of_range("large");否則才輸出 exc1。函式本身可以拋出例外,呼叫端負責捕捉或讓例外繼續傳遞,這是合法的 C++ 寫法。
f2:有問題
f2 呼叫 f1(-1),因此 f1 拋出 out_of_range。f2 沒有捕捉例外,例外便繼續傳到 main。而 main 也沒有 try-catch,程式會在此終止,後續函式不會執行。
f3:沒有問題
f1(-1) 拋出的 out_of_range 會被 catch(exception &e) 捕捉,因為 out_of_range 是 exception 的衍
第 三 題25 分
針對下列 Java 程式碼,請完成統一塑模語言(UML)類別圖 (a)~(e);另外請標示出錯誤程式碼行數並說明錯誤原因;以及說明若將錯誤行數程式碼予以註解後,執行其程式的輸出。
import java.io.*;
interface Pet { public abstract int eat(int f); };
class Dog implements Pet { public Dog(int f) { food = f; }
public int eat(int f) {
food += f;
return food;
}
private int food;
};
public class Main { public static void main(String[] args) { Pet d1 = new Pet(); Pet d2 = new Dog(); Pet d3 = new Dog(5); d1.eat(5); d2.eat(5); System.out.println("dog: "+d3.eat(5)); } }
UML 類別圖中的空格:
核心觀念
本題考查 Java 介面、類別實作、建構子、封裝,以及 UML 類別圖表示法:
- 介面以
<<interface>>標示。 - 類別實作介面,使用 UML「實作關係(realization)」表示:虛線加空心三角形,三角形指向介面。
public在 UML 中以+表示,private以-表示。- 方法格式通常寫成
+ 方法名(參數名:型別):回傳型別。 - 建構子名稱與類別相同,且沒有回傳型別。
UML 類別圖填答
(a) Pet 的類別/介面標示
<<interface>>
Pet 是介面,因此應在名稱 Pet 上方標示 <<interface>>。
(b) Pet 的方法
+ eat(f:int):int
原始宣告為:
public abstract int eat(int f);
因此:
public對應+- 參數
f的型別為int - 回傳型別為
int
介面方法也可用斜體表示其抽象性。
(c) Pet 與 Dog 之間的關係
實作關係(Realization)
UML 表示方式為:
- 從
Dog指向Pet - 使用虛線
- 線末端為空心三角形
因為程式碼為:
class Dog implements Pet
(d) Dog 的屬性
- food:int
原始宣告為:
private int food;
private 對應 UML 的 -。
(e) Dog 的方法
+ eat(f:int):int
原始方法為:
public int eat(int f)
圖中已列出的建構子若要完全依照程式碼,應為:
+ Dog(f:int)
因為程式只有:
public Dog(int f)
並沒有無參數建構子 Dog。因此圖中若印成 + Dog,該處的參數資訊是不完整或不正確的;空格 (e) 應填入 + eat(f:int):int。
錯誤程式碼行數與原因
第 15 行
第 四 題25 分
針對下列 Python 程式碼,依序在兩個 Terminal 執行 server.py 和 client.py 後,在 client.py 輸入 Tom 和 quit;請說明 client.py 的 Terminal 之輸出內容,並說明 Line 03、04、05 程式碼的運作邏輯。
server.py:
server.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 7000)) s.listen(5) print('wait for connection...')
while True: conn, addr = s.accept() print('connected by ' + str(addr)) indata = conn.recv(1024) print('recv: ' + indata.decode())
if 'quit' in indata.decode():
outdata = 'bye'
else:
outdata = 'hi ' + indata.decode()
conn.send(outdata.encode())
conn.close()
if 'quit' in indata.decode():
break
print('listen...')
s.close()
client.py:
client.py
import socket
while True: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 7000)) name = input('>name:') print('send:' + name) s.send(name.encode()) indata = s.recv(1024) s.close() print('>' + indata.decode())
if 'quit' in name:
break
登入後即可作答並保存紀錄。
核心觀念
本題考查 TCP Socket 用戶端與伺服器端的基本通訊流程,以及字串、位元組資料的轉換:
socket.AF_INET表示使用 IPv4;socket.SOCK_STREAM表示使用 TCP。send傳送位元組資料,因此字串須先用encode編碼;recv收到位元組資料,須用decode轉回字串。accept接受一個用戶端連線;close關閉該次連線。- 伺服器收到
quit後,回覆bye,並結束伺服器的迴圈。
解題方法
依序追蹤每次迴圈中的執行順序:用戶端建立連線、讀取輸入、傳送資料、接收伺服器回覆,最後判斷是否輸入 quit。伺服器則對每次連線接收一筆資料、依內容回覆,若內容含有 quit,便離開伺服器迴圈。
第一次輸入:Tom
- 用戶端連線到伺服器,輸入
Tom。 - 用戶端印出
send:Tom,並傳送字串Tom編碼後的位元組。 - 伺服器收到資料,因為內容不含
quit,回覆hi Tom。 - 用戶端收到回覆並關閉此次連線,印出
>hi Tom。 - 用戶端判斷
quit不在Tom中,因此進入下一輪。
第二次輸入:quit
- 用戶端重新建立連線,輸入
quit。 - 用戶端印出
send:quit,並傳送資料。 - 伺服器收到資料,因為內容含有
quit,回覆bye,接著關閉此次連線並跳出伺服器迴圈。 - 用戶端收到回覆並關閉此次連線,印出
>bye。 - 用戶端判斷
quit在輸入內容中,因此跳出用戶端迴圈。
client.py Terminal 輸出
假設兩個 Terminal 均正常啟動,伺服器已在等待連線,且輸入內容恰為 Tom、quit,用戶端 Terminal 的輸出如下(輸入內容由使用者在提示符後輸入):
>name:Tom
send:Tom
>hi Tom
>name:quit
send:quit
>bye