1. 程式人生 > >【 C 】初識函式指標

【 C 】初識函式指標

函式指標,顧名思義,也就是指標,不過這個指標是指向函式的指標。

接下來的一個宣告更有趣,但也更容易讓人疑惑:

int (*f)();

確定括號的含義是分析這個宣告的一個重要步驟。這個宣告有兩個括號,每對的含義各不相同。第2個括號是函式呼叫操作符,第1個括號只起到聚組的作用。它迫使間接訪問在函式呼叫之前進行,使 f 成為一個函式指標,它所指向的函式返回一個整型值。

何為函式指標?

程式中的每個函式都位於記憶體中的某個位置,所以存在指向那個位置的指標是完全可能的。

如果上面的引用不清楚的話,我在試著解釋一遍:

int (*f)();

先執行括號裡面的內容,也就是間接訪問操作,可見 f 是一個指標,可是之後就進行函式呼叫的操作,可見該指標是還不是一般的指標,該指標指向一個函式,稱該指標為函式指標。

函式指標有什麼用呢?最常見的兩個用途是轉換表(jump table)和作為引數傳遞給另一個函式。但是本博文不涉及其應用,只是簡單地瞭解一下函式指標以及函式指標的初始化!

必須提出,和其他型別的指標一樣,簡單宣告一個函式指標並不意味著可以馬上使用,對函式指標執行間接訪問之前必須初始化為指向某個具體的函式。而這個過程十分的有意思,下面的程式碼說明了一種初始化函式指標的方法:

int f( int );
int (*pf)( int ) = &f;

第2個宣告建立了一個函式指標並把它初始化為指向函式 f 。這裡關鍵的問題是:在函式初始化之前具有 f 的原型是很重要的,否則編譯器就無法檢測 f 的型別是否與 pf 所指向的型別一致。

下面更有意思的內容來了:

初始化表示式中的 &(取地址操作符)是可選的,因為函式名被使用時總是由編譯器把它轉換為函式指標。&操作符只是顯式地說明了編譯器隱式執行的任務。

在函式指標被宣告以及初始化之後,我們就可以使用三種方式來呼叫函式:

int ans;

ans = f( 25 );
ans = (*pf)(25);
ans = pf(25);

這三種方式呼叫函式完成的功能是完全相同的,這看起來有些荒謬,特別是第三條,而實際上並非如你所想,下面一一道來:

第1條語句簡單地使用名字來呼叫函式,這是我們最常用的呼叫函式的方法,但它的執行過程可能和你想象的不太一樣。函式名f首先被轉化為一個函式指標,該指標指定函式在記憶體中的位置。然後,函式呼叫操作符()呼叫該函式,執行開始於這個地址的程式碼。

第2條語句對pf執行間接訪問操作,它把函式指標轉化為一個函式名。這個轉換並不是真正需要的,因為編譯器在執行函式呼叫操作符之前又會把它轉換回去。

第3條語句和前兩天語句效果一樣,只不過省去了在第1種情況下,編譯器把函式名 f 轉換為函式指標的過程,這裡是直接執行函式在該處的程式碼。

仔細品味這些說明,真是大開眼界!