C語言指標與函式指標完整教學:基礎觀念、實用範例與安全須知

1. 簡介

C語言的指標(Pointer)與函式指標(Function Pointer)是實現高效且靈活程式設計不可或缺的要素。指標可以直接操作記憶體位址,函式指標則能儲存函式的位址,進而實現間接呼叫。本篇文章將從基礎到應用詳細說明指標與函式指標,並介紹相關的安全性議題與實用範例。

2. 指標的基礎

2.1 什麼是指標

指標是一種特殊的變數,用來儲存其他變數在記憶體中的位址。使用指標可以間接存取變數的值,讓程式設計更具彈性。例如,可用於函式間資料共享,或高效處理大型資料結構。

2.2 指標的宣告與用法

宣告指標時,在資料型態前加上星號(*)。範例如下:

int x = 5;
int* p = &x;  // 將 x 的位址存入指標 p

& 運算子取得變數的位址,* 運算子則存取指標所指向的值。

printf("%d", *p);  // 輸出: 5

p 指向 x 的位址,使用 *p 可取得 x 的值。

侍エンジニア塾

3. 函式指標的基礎

3.1 函式指標的定義與宣告

函式指標是一種用來儲存函式位址的指標,可用於動態呼叫不同函式。宣告時需指定函式的回傳型態與參數型態。

int (*funcPtr)(int);

這是指向一個帶有 int 參數並回傳 int 的函式的指標。

3.2 函式指標的使用方式

要透過函式指標呼叫函式,需先將函式位址賦值給指標,然後直接以指標方式呼叫。

int square(int x) {
    return x * x;
}

int main() {
    int (*funcPtr)(int) = square;
    printf("%d", funcPtr(5));  // 輸出: 25
    return 0;
}

在這個例子中,funcPtr 儲存了 square 函式的位址,並可透過 funcPtr(5) 呼叫該函式。

4. 函式指標的應用範例

4.1 透過函式指標執行函式

函式指標特別適合建立函式陣列,可根據不同情境於執行時選擇要執行的函式,提升程式彈性。

void hello() {
    printf("Hello\n");
}

void goodbye() {
    printf("Goodbye\n");
}

int main() {
    void (*funcs[2])() = {hello, goodbye};
    funcs[0]();  // 輸出: Hello
    funcs[1]();  // 輸出: Goodbye
    return 0;
}

此範例將不同函式存入 funcs 陣列,並可根據需求動態執行。

4.2 回呼函式(Callback Function)

回呼函式是一種在特定事件發生時執行的函式,可動態改變程式部分行為。

void executeCallback(void (*callback)()) {
    callback();
}

void onEvent() {
    printf("Event occurred!\n");
}

int main() {
    executeCallback(onEvent);  // 輸出: Event occurred!
    return 0;
}

透過 executeCallback 函式可動態傳入不同函式並執行。

5. 指標與結構體

5.1 結構體指標的使用方法

使用結構體指標可有效處理大型資料結構。存取結構體指標成員時,請使用「->」運算子。

typedef struct {
    int x;
    int y;
} Point;

int main() {
    Point p = {10, 20};
    Point *pPtr = &p;

    printf("%d, %d", pPtr->x, pPtr->y);  // 輸出: 10, 20
    return 0;
}

pPtr->x 代表存取 p 結構體的成員 x

5.2 將結構體指標傳遞給函式

將結構體指標作為參數傳遞給函式,可在函式內操作該結構體的成員。

void updatePoint(Point *p) {
    p->x += 10;
    p->y += 20;
}

int main() {
    Point p = {10, 20};
    updatePoint(&p);
    printf("%d, %d", p.x, p.y);  // 輸出: 20, 40
    return 0;
}

本範例於 updatePoint 函式中直接修改 Point 結構體成員。

6. 函式指標的優點與注意事項

6.1 優點

使用函式指標可大幅提升程式的擴充性與彈性。例如,可用於實作外掛系統或事件驅動程式設計,動態切換不同函式。透過函式指標陣列,也能將複雜的 switch 敘述簡化成單純的迴圈。

6.2 注意事項

使用函式指標時,需注意以下幾點:

  • 型態必須一致:若函式指標型態不正確,可能造成預期外行為。請確認函式原型完全一致。
  • 安全風險:呼叫無效的函式指標,可能導致 segmentation fault 等錯誤。請務必初始化指標並在需要時檢查 NULL
  • 間接取值風險:若未確認指標有效性就取值,程式可能當機。

7. 總結

熟悉 C 語言中的指標與函式指標,是實現高效且靈活程式設計的關鍵。透過函式指標,可實作動態函式呼叫、事件驅動設計等進階技巧。請確實理解從基礎到應用的概念,並安全地運用指標於實際開發中。