首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C/C++ 指標函數與函數指標完整指南:語法、陷阱與實戰模式

     編輯:C++ 入門

引言:兩個極易混淆的概念

「指標函數」與「函數指標」僅一字之差,卻是截然不同的實體。搞混它們是 C/C++ 學習者的通病。本文從語法解析、記憶體模型、呼叫慣例到實戰模式,徹底釐清兩者差異,並延伸至多級指標與指標陣列技巧。

一、指標函數:回傳指標的函數

1.1 定義與語法

本質:一個函數,其回傳型別是指標。
宣告格式:型別 *函數名(參數列表);


int* GetData();           // 回傳 int*
int* Transform(int, int); // 回傳 int*

1.2 典型用途:回傳陣列元素位址或靜態資源


int* GetDate(int week, int day) {
    static int calendar[5][7] = { /* ... */ };
    return &calendar[week-1][day-1]; // 回傳靜態陣列元素位址,生命週期覆蓋全程式
}

關鍵點:回傳的指標必須指向**存活期超過函數呼叫**的記憶體(靜態、全域、堆、呼叫端傳入的緩衝區)。**嚴禁回傳區域變數位址**。

二、函數指標:指向函數的指標

2.1 定義與語法

本質:一個變數,儲存函數的**進入位址**,可透過它間接呼叫函數。
宣告格式:型別 (*指標變數名)(參數列表); —— 括號不可省略,否則變成指標函數宣告。


void (*funcPtr)();        // 指向無參無回傳函數
int  (*cmp)(const void*, const void*); // 指向比較函數 (如 qsort 回調)

2.2 賦值與呼叫


void FileFunc()  { puts("FileFunc"); }
void EditFunc()  { puts("EditFunc"); }

void (*fp)() = FileFunc;  // 取址 & 可省略
fp();                     // 呼叫:相當於 FileFunc()
(*fp)();                  // 明確解引用風格,兩者等價

fp = EditFunc;
fp();                     // 呼叫 EditFunc()

2.3 核心應用場景

  • 回調函數:qsort、bsearch、事件處理、訊號槽。
  • 狀態機/策略模式:運行期切換演算法實作。
  • 動態載入:dlopen/GetProcAddress 取得函數位址賦值給函數指標。
  • 虛函數表手工實作:C 語言模擬多型。

三、語法解析器視角:右左法則

讀懂複雜宣告的通用口訣:從變數名起始,向右讀到盡頭,再向左,遇到括號優先處理括號內。

宣告解讀步驟含義
int *fp();fp → () → * → int函數,回傳 int*
int (*fp)();fp → * → () → int指標,指向回傳 int 的函數
int *(*fp[])();fp → [] → * → () → * → int陣列,元素是指向回傳 int* 函數的指標
int (*(*fp)[])();fp → * → [] → * → () → int指標,指向陣列,陣列元素是指向回傳 int 函數的指標

四、延伸:多級指標與指標陣列

4.1 指標的指標


char c = 'A';
char *p  = &c;      // 一級指標
char **pp = &p;     // 二級指標,指向 p

*p  = 'B';          // 修改 c
**pp = 'C';         // 透過 pp 修改 c
*pp = &otherChar;   // 修改 p 指向

實戰用途:

  • 函數修改呼叫端的指標值(如 void FindCredit(int**) 移動指標掃描陣列)。
  • 動態二維陣列:int** matrix = new int*[rows]; for(i) matrix[i] = new int[cols];
  • main(int argc, char** argv):命令列參數陣列。

4.2 指向指標陣列的指標


char* names[] = { "Bill", "Sam", "Jim", "Paul", nullptr };
char** nm = names; // nm 指向首元素

while (*nm) {
    puts(*nm); // 印出字串
    ++nm;      // 移至下一個 char*
}

以 nullptr 作哨兵,無需額外傳遞長度,彈性增刪元素。

五、現代 C++ 替代方案

  • 函數指標 → std::function<R(Args...)> + Lambda/仿函數,支援捕獲狀態、類型擦除。
  • 指標函數回傳陣列 → 回傳 std::vector<T>、std::array<T,N>、std::span<T> (C++20),避免手動生命週期管理。
  • 多級指標 → 容器嵌套(vector<vector<T>>)或扁平化 vector<T> + 索引運算。

結語

指標函數是「函數」,函數指標是「變數」。掌握宣告語法的右左法則、生命週期契約與現代替代工具,即可從容駕馭這對經典難點,寫出型別安全、資源無洩漏的程式碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved