[面試攻略] 技術性考題:函數指標(Function Pointer)

更新於 發佈於 閱讀時間約 10 分鐘

函數指標(Function Pointer)是一個常見的技術面試題目,特別在C或C++相關的職位中,用來考驗你對程式設計中函數作為一等公民(first-class citizen)的理解,以及記憶體管理和程式控制流的掌握。


問題描述

函數指標是一個儲存函數位址的變數,通過它可以間接呼叫函數。面試中,題目可能要求你:

  1. 定義並使用函數指標。
  2. 通過函數指標實現靈活的函數調用(例如,傳遞不同行為的函數)。
  3. 解釋函數指標的用途或底層原理。

典型題目範例

  • 寫一個程式,使用函數指標來選擇性地執行加法或減法。
  • 實現一個排序函數,通過函數指標傳入比較函數。
  • 解釋函數指標與一般指標的區別。

範例需求: 給定兩個整數 a 和 b,以及一個操作(加法或減法),使用函數指標來執行指定的操作並返回結果。


解法

  1. 定義函數指標
    • 在C中,函數指標的語法為:return_type (*pointer_name)(parameter_types)。 例如,指向一個接受兩個整數並返回整數的函數:int (*func_ptr)(int, int)
  2. 實現具體函數
    • 定義加法和減法函數,簽名一致。
  3. 使用函數指標
    • 將函數位址賦值給函數指標。 通過函數指標呼叫函數。
  4. 靈活選擇
    • 根據輸入選擇不同的函數指標。


程式碼(C語言)

以下是一個實現加法或減法選擇的範例:

#include <stdio.h>

// 定義加法和減法函數,簽名一致
int add(int a, int b) {
return a + b;
}

int subtract(int a, int b) {
return a - b;
}

// 定義操作函數,使用函數指標
int operate(int a, int b, int (*func_ptr)(int, int)) {
return func_ptr(a, b); // 通過函數指標呼叫
}

int main() {
int a = 10, b = 5;

// 定義函數指標並賦值
int (*operation)(int, int);

// 選擇加法
operation = add;
printf("Add: %d\n", operate(a, b, operation)); // 輸出 15

// 選擇減法
operation = subtract;
printf("Subtract: %d\n", operate(a, b, operation)); // 輸出 5

// 直接傳遞函數位址
printf("Add (direct): %d\n", operate(a, b, add)); // 輸出 15

return 0;
}


程式碼解釋

  1. 函數定義
    • add 和 subtract 是兩個簡單的函數,接受兩個整數並返回結果。 它們的簽名必須與函數指標的簽名一致。
  2. 函數指標
    • int (*func_ptr)(int, int) 定義了一個函數指標,指向返回 int 並接受兩個 int 參數的函數。 在 operate 函數中,func_ptr 用來呼叫傳入的函數。
  3. 靈活調用
    • 在 main 中,通過將 add 或 subtract 的位址賦值給 operation,實現動態選擇。 也可以直接傳遞函數名(如 add),因為函數名在C中會自動轉換為函數位址。
  4. 輸出
    • 程式展示如何通過函數指標執行不同操作。


時間與空間複雜度

  • 時間複雜度:O(1)(函數指標的賦值和呼叫是常數時間操作)。
  • 空間複雜度:O(1)(僅儲存一個函數指標,通常是固定大小,如8字節在64位系統上)。


函數指標的用途

面試中可能會問到函數指標的實際應用,這些是常見場景:

  1. 回調函數(Callbacks)
    • 例如,在事件驅動程式設計中,註冊回調函數以響應事件。
  2. 函數表(Function Table)
    • 實現動態分派,例如模擬物件導向的虛函數表。
  3. 靈活的API設計
    • 允許用戶傳入自定義行為,例如C標準庫的 qsort 使用比較函數指標。
  4. 模組化程式設計
    • 將不同功能解耦,通過函數指標動態選擇實現。


面試中的注意事項

  1. 澄清語法
    • 函數指標的語法可能讓人困惑,面試時先寫出簽名並確認:
int (*func_ptr)(int, int); // 正確
int *func_ptr(int, int); // 錯誤,這是返回 int* 的函數
    • 注意括號的使用,*func_ptr 必須括起來以區分優先級。
  1. 講解原理
    • 說明函數指標儲存的是函數的記憶體位址(程式碼段中的位址)。 提到函數名(如 add)在C中會自動轉為位址,因此 operation = add 等價於 operation = &add。 呼叫時,(*func_ptr)(a, b) 和 func_ptr(a, b) 都是合法的。
  2. 邊界檢查
    • 檢查函數指標是否為空(if (func_ptr == NULL)),避免未定義行為。 確保傳入的函數簽名一致,否則編譯器可能報錯或導致運行時錯誤。
  3. 進階討論
    • 如果面試官問到C++,提到函數指標與 std::function 或函數物件(functor)的區別: std::function 更靈活,支持lambda、成員函數等。 函數指標更輕量,但只能指向普通函數。 提到型別安全:C的函數指標缺乏型別檢查,C++中可用模板或 std::function 改善。
  4. 乾淨程式碼
    • 使用有意義的變數名(如 operation 而不是 fp)。 註釋關鍵步驟,特別是函數指標的定義和使用。 確保程式碼簡單且易於理解。


可能的追問

  1. 如何實現一個回調系統?
    • 定義一個函數指標陣列,儲存多個回調函數,根據事件觸發相應函數。
  2. 函數指標與虛函數的比較?
    • 函數指標是靜態綁定,虛函數是動態綁定(通過虛表實現)。 虛函數更適合物件導向,函數指標更通用但手動管理。
  3. 如何處理多個參數或不同簽名?
    • 使用 void* 傳遞上下文(需小心型別轉換)。 在C++中,使用模板或 std::function 處理不同簽名。
  4. 性能影響?
    • 函數指標的間接呼叫可能略微增加開銷(因位址解引用)。 現代編譯器通常會內聯小函數,減少影響。


程式碼進階範例(模擬qsort的比較器)

以下是一個更接近實際應用的範例,展示函數指標在排序中的使用:

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

// 升序比較
int compare_asc(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}

// 降序比較
int compare_desc(const void* a, const void* b) {
return (*(int*)b - *(int*)a);
}

int main() {
int arr[] = {5, 2, 9, 1, 5};
int n = 5;

// 升序排序
qsort(arr, n, sizeof(int), compare_asc);
printf("Ascending: ");
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");

// 降序排序
qsort(arr, n, sizeof(int), compare_desc);
printf("Descending: ");
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");

return 0;
}

輸出

Ascending: 1 2 5 5 9
Descending: 9 5 5 2 1


練習建議

  • 練習手寫函數指標的定義和使用,避免語法錯誤。
  • 實現一個簡單的回調系統,例如事件處理器。
  • 閱讀C標準庫中 qsort 或 signal 的文件,理解函數指標的應用。
  • 如果熟悉C++,比較函數指標與 std::function 或lambda的用法。


留言
avatar-img
留言分享你的想法!
avatar-img
追極光的北極熊|軟體工程師的小天地
9會員
143內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
2025/05/10
在C++中,函數執行時的記憶體配置涉及程式如何在記憶體中儲存變數、參數和程式碼。這是面試常見題目,因為它直接關係到程式效率和資源管理。本文將介紹函數記憶體配置的基礎、C++程式碼範例、關鍵概念,以及面試答題技巧。
2025/05/10
在C++中,函數執行時的記憶體配置涉及程式如何在記憶體中儲存變數、參數和程式碼。這是面試常見題目,因為它直接關係到程式效率和資源管理。本文將介紹函數記憶體配置的基礎、C++程式碼範例、關鍵概念,以及面試答題技巧。
2025/05/02
矩陣相乘是一個經典的演算法問題,經常出現在技術面試中,用來評估你對多維陣列的操作和程式設計邏輯的掌握。本文將以標準矩陣相乘為例,介紹其基礎概念、Python程式碼、時間與空間複雜度,並提供面試應答技巧。
2025/05/02
矩陣相乘是一個經典的演算法問題,經常出現在技術面試中,用來評估你對多維陣列的操作和程式設計邏輯的掌握。本文將以標準矩陣相乘為例,介紹其基礎概念、Python程式碼、時間與空間複雜度,並提供面試應答技巧。
2025/04/24
排序演算法是將一組資料(如數字陣列)按特定順序(通常是遞增或遞減)排列的過程。以下介紹五種面試常見的排序演算法,包含簡單說明、程式碼範例、時間與空間複雜度,以及面試答題技巧。所有程式碼使用Python,因為它語法簡潔,適合快速理解和白板 coding。
2025/04/24
排序演算法是將一組資料(如數字陣列)按特定順序(通常是遞增或遞減)排列的過程。以下介紹五種面試常見的排序演算法,包含簡單說明、程式碼範例、時間與空間複雜度,以及面試答題技巧。所有程式碼使用Python,因為它語法簡潔,適合快速理解和白板 coding。
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
介紹朋友新開的蝦皮選物店『10樓2選物店』,並分享方格子與蝦皮合作的分潤計畫,註冊流程簡單,0成本、無綁約,推薦給想增加收入的讀者。
Thumbnail
介紹朋友新開的蝦皮選物店『10樓2選物店』,並分享方格子與蝦皮合作的分潤計畫,註冊流程簡單,0成本、無綁約,推薦給想增加收入的讀者。
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
高中數學主題練習—對數方程式
Thumbnail
高中數學主題練習—對數方程式
Thumbnail
C 語言的函式庫定義了許多好用的函式,在寫 C++ 的時候可以拿來用。這是因為 C++ 當初在設計的時候,就有刻意把 C 涵蓋進來。 基本用法 首先要導入 C 語言的標準函式庫: #include <cstdlib> 以 c 作為開頭表示它是 C 語言的函式庫,只是被我們拿來 C++ 的程式
Thumbnail
C 語言的函式庫定義了許多好用的函式,在寫 C++ 的時候可以拿來用。這是因為 C++ 當初在設計的時候,就有刻意把 C 涵蓋進來。 基本用法 首先要導入 C 語言的標準函式庫: #include <cstdlib> 以 c 作為開頭表示它是 C 語言的函式庫,只是被我們拿來 C++ 的程式
Thumbnail
高中數學主題練習—C計算(一)
Thumbnail
高中數學主題練習—C計算(一)
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News