112 地方特考四等 資訊處理類科 程式設計概要 考古題詳解

112 年・地方特考・四等・資訊處理類科
試題代碼 程式設計概要

第 一 題30 分

一、撰寫遞迴函式是重要程式設計技巧之一。

(一) 請說明下列遞迴函式 findnum 目的為何?(5 分)

int items, price[100];  // 全域變數

int findnum (int i, int num) {
    if (i < items) {
        if (num < price[i])
            num = price[i];
        num = findnum (i+1, num);
    }
    return num;
}

主程式如下:

int main() {
    int i, num;

    // 讀入數量及所有正整數價格
    scanf("%d", &items);

    for (i=0; i<items; i++)
        scanf("%d", &price[i]);

    num = findnum (0, -1);
    printf ("The ... is %d\n", num);

    return 0;
}

(二) 請將 findnum() 函式改寫成非遞迴的函式。(10 分)

(三) 請說明下列非遞迴程式目的為何?(5 分)

void convert (long m) {
    long count=-1, n=0;

    while (0 < m) {
        n = n*10 + m%2;
        m = m / 2;
        count++;
    }

    while (0 < count) {
        printf ("%ld", n%10);
        n = n / 10;
        count--;
    }

    printf ("%ld", n%10);
    return;
}

主程式如下:

int main() {
    long m;

    scanf("%ld",&m);
    printf ("The ... value is ");
    convert (m);
    printf ("\n");

    return 0;
}

(四) 請將 convert() 函式改寫成以遞迴運算的函式,且函式內不可新增變數。(10 分)

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

這一題的完整詳解

核心觀念:逐一比較並保留目前最大值

函式從第 i 個價格開始檢查。若 num 小於 price[i],就把 num 更新成該價格;接著遞迴檢查下一個價格。當 i 不再小於 items 時,遞迴停止並回傳 num。

因此,呼叫 findnum(0, -1) 會逐一比較所有價格,回傳所有價格中的最大值。題目說價格為正整數,所以初始值 -1 小於每個價格,不會影響最大值的判定。

(二) 改寫為非遞迴函式

解題方法:用迴圈取代每次「檢查一筆,再呼叫下一層」的遞迴

遞迴參數 i 對應迴圈索引;參數 num 則是目前找到的最大值,改寫後以區域變數保存。

int findnum(int i, int num) {
 while (i < items) {
 if (num < price[i])
 num = price[i];
 i++;
 }
 return num;
}

此版本保留原函式的參數及回傳方式。主程式仍以 findnum(0, -1) 呼叫即可。

(三) convert 的目的

核心觀念:用十進位整數暫存二進位各位數,再由高位到低位輸出

第一個 while 反覆以 m % 2 取得餘數,也就是目前最低位的二進位數字,並用

n=10n+(m mod 2)n = 10n + (m \bmod 2)

將餘數接到十進位整數 n 的末尾;接著以整數除法 m = m / 2 取得下一個商。這個過程相當於將正整數 m 轉換成二進位表示,但二進位位數以十進位數字的形式反向累積在 n 中。

第二個 while 每次輸出 n % 10,再將 n 除以 1010,逐位印出 n 的末尾數字。由於第一次迴圈所存的位數順序相反,這樣輸出後便會得到由高位到低位的二進位表示。

🔒

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

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

免費註冊

第 二 題20 分

二、請說明下列 PHP 程式設計的觀念。

(一) Class 和 Interface 的差異為何?請從「可否宣告屬性」、「可否實例化」、「可否有實作方法」3 個面向加以說明。(5 分)

(二) 若前端網頁以 HTML 程式上傳一個檔案到後端,請以 PHP 寫出後端要處理的部分,包括檢查檔案是否上傳成功、檢查檔案是否存在(不可覆蓋)、將上傳的檔案搬移到指定位置。(15 分)

前端:

<form method="post" enctype="multipart/form-data" action="upload.php">
    <input type="file" name="to be uploaded">
    <input type="submit" value="Upload">
</form>

後端:

<?php

...

?>

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

這一題的完整詳解

核心觀念

本題考 PHP 物件導向中的 class 與 interface,以及透過 $_FILES 接收並安全儲存上傳檔案。

(一)Class 與 Interface

比較面向ClassInterface
可否宣告屬性可以宣告屬性,例如 $name。不可宣告一般物件屬性;可宣告常數及方法簽章。
可否實例化可直接實例化非抽象類別。不可直接實例化。
可否有實作方法可以包含已實作的方法,也可以包含抽象方法。方法主要用來規定實作契約;實作介面的類別須提供介面方法的實作。

類別可用 implements 實作介面;同一個類別可以實作多個介面,但 PHP 類別只能直接繼承一個父類別。

解題方法

(一)Class 與 Interface 作答要點

依題目指定的三個面向分別比較即可。要留意「不可實例化」不只可能用來描述介面,也適用於抽象類別;但一般可實例化的是非抽象類別。介面則定義一組方法契約,讓實作它的類別遵守。

(二)PHP 檔案上傳

表單使用 method="post" 與 enctype="multipart/form-data",因此 PHP 會將上傳資料放在 $_FILES。檔案欄位名稱含空格,後端必須以 $_FILES['to be uploaded'] 取值。

以下程式會依序確認欄位存在、檢查上傳錯誤碼、確認目的檔案不存在,再將暫存檔搬移到指定位置:

🔒

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

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

免費註冊

第 三 題20 分

三、請說明下列程式設計概念的差異。(每小題 5 分,共 20 分)

(一) 請說明傳址(call-by-reference)與傳值(call-by-value)參數傳遞的差異。

(二) 請說明靜態及動態記憶體(static memory allocation vs. dynamic memory allocation)配置的主要差別。

(三) 請說明語法錯誤(syntax error)、語意錯誤(semantic error)、執行錯誤(run-time error)的主要差別。

(四) 上述的錯誤,編譯程式過程中可以發現的是那一種錯誤(可複選)?

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

這一題的完整詳解

**核心觀念:**兩者差別在於函式取得的是「引數的值」,還是「可存取原變數的參照」。

  • 傳值(call-by-value):呼叫函式時,將引數的值複製給形式參數。函式內修改形式參數,只會改變副本,不會直接改變呼叫端的原變數。
  • 傳址(call-by-reference):形式參數參照呼叫端的原變數。函式內透過該參數修改內容,呼叫端看到的原變數也會改變。

**解題方法:**判斷函式修改參數後,呼叫端原變數是否改變:不改變是傳值;會改變是傳址。

程序 f(x):x = 10

a = 3
f(a)

若為傳值,f 修改的是 a 的副本,a 仍為 3;若為傳址,x 參照 a,a 會變成 10。

**解題技巧:**不要只看參數名稱或呼叫方式;關鍵是參數是否對應到呼叫端原變數。傳值雖不直接改變原變數,但若傳遞的是物件參照等複合資料,函式仍可能透過該參照修改物件內容,須依語言的參數傳遞規則判斷。

(二)靜態與動態記憶體配置

**核心觀念:**主要差別是配置的時間、大小是否能依執行時需求決定,以及記憶體的生命週期如何管理。

  • 靜態記憶體配置(static memory allocation):記憶體空間與大小通常在編譯或載入時決定,執行期間不會依需求改變。例如固定大小的全域變數或靜態變數。
  • 動態記憶體配置(dynamic memory allocation):程式執行期間依需求向記憶體管理機制取得空間,大小可依執行時資料決定;不再需要時,須由程式釋放,或交由垃圾回收機制處理。常見配置來源為堆積區(heap)。

**解題方法:**比較配置時間與大小決定時點:編譯或載入時已確定,屬靜態配置;執行時才取得,屬動態配置。

解題技巧:「靜態」不等於程式執行時完全沒有記憶體配置;此處指配置的時間與大小通常預先確定。動態配置也不代表一定要手動釋放,管理方式取決於程式語言。

(三)語法錯誤、語意錯誤與執行錯誤

**核心觀念:**三者分別是程式不符合文法、語句意義或型別規則不正確,以及程式執行時發生異常。

🔒

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

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

免費註冊

第 四 題30 分

四、超商預計發展合併集點卡程式,說明如下。

若有 nn 張集點卡要合併,但只能兩張兩張合併,因此共需合併 n−1n-1 次才能把點數全部集中到一張卡。兩張合併時會扣掉較少點數那張的 110\frac{1}{10} 點數(無條件進位至整數)做為手續費。

例如,若有 AA、BB、CC 3 張集點卡要合併,且點數分別為 25、30、51 點。若先合併 AA、BB,再合併 CC,則會扣掉 3+63+6 點,因此合併後剩 97 點,這也剛好是最差合併策略下的合併總點數;但在最佳的合併策略下(先合併 BB、CC,再合併 AA),則可有 100 點。

每小題 15 分,共 30 分。

(一) 請寫 best_case() 函式,計算 nn 張集點卡合併過後最多可有多少點數。

(二) 請寫 worst_case() 函式,計算 nn 張集點卡合併過後最少可有多少點數。

#include <stdio.h>

int a[101], n;  // 最多可有 100 張集點卡要合併,實際上要合併 n 張卡

int best_case () {
    ...
}

int worst_case () {
    ...
}

int main () {
    scanf ("%d", &n);

    for (i=0; i<n; i++)
        scanf ("%d", &a[i]);

    printf ("Best case: %d points\n", best_case());
    printf ("Worst case: %d points\n", worst_case());

    return 0;
}

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

這一題的完整詳解

核心觀念

每次合併兩張卡,手續費是點數較少者的十分之一,並無條件進位:

手續費=⌈min⁡(x,y)10⌉\text{手續費}=\left\lceil \frac{\min(x,y)}{10}\right\rceil

合併後的點數為 x+y−手續費x+y-\text{手續費}。因為手續費取決於兩張卡在每一步的點數,合併順序會影響最後點數。

解題方法

題目已指出合併 nn 張卡需做 n−1n-1 次,因此可逐次選擇要合併的兩張卡,再把合併結果放回卡片集合。

要找最多點數時,每次應選點數最多的兩張卡合併;要找最少點數時,每次應選點數最少的兩張卡合併。可用排序或優先佇列維護卡片點數,每次取出指定的兩張,計算新點數後放回,直到剩下一張。

🔒

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

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

免費註冊

其他考古題