第一部分 什麼是函數指針
1.1 函數指針概念
1.2 函數指針與指針函數,數組指針與指針數組
1.3 函數指針的作用
第二部分 函數指針的初始化及使用
2.1 初始化函數指針
2.2 函數名究竟是什麼
#include <stdio.h>
int test(void );
int main(void )
{
printf( " test=%p\n",test);
printf( "&test=%p\n",&test);
printf( "*test=%p\n",*test);
return 0;
}
int test(void )
{
printf( "test invoked!");
return 0;
}
|
2.3typedef可以用於定義函數指針類型
要說明一下,對於typedef int (*ptf) (double*,char); 注意不要用#define的思維來看待typedef,如果用 #define的思維來看的話會以爲 (*ptf)(double*, char)是int的別名,但這樣的別名看起來好像又不是合法的名字,於是會處於迷茫狀態。實際上,上面的語句把 ptf定義爲一種函數指針類型的別名,它和函數指針類型 int (*) (double*, char);等價,也就是說ptf現在也是一種類型。
下面分析一個函數指針和指針函數結合的例子:
void (*signal (int sig, void (*func) (intsiga)) ) ( int siga );
看上去確實有些複雜,讓我們來分析。現在要分析的是 signal,因爲緊鄰 signal的是優先級最高的括號,首先與括號結合,所以 signal爲一個函數,括號內爲 signal的兩個形參,一個爲 int型,一個爲指向函數的指針。接下來從向左看, *表示指向某對象的指針,它所處的位置表明它是 signal的返回值類型,現在可以把已經分析過的 signal整體去掉,得到 void (*) ( int siga ),很清晰了吧。又是一個函數指針,這個指針與 signal形參表中的第二個參數類型一樣,都是指向接受一個 int型形參且不返回任何值的函數的指針。同樣地,用 typedef可以將這個聲明簡化:
typedef void (*p_sig) (int);
p_sig signal(int sig, p_sig func);
這個signal 函數是C語言的庫函數,在 signal.h中定義,用來處理系統中產生的信號,是 UNIX/Linux編程中經常用到的一個函數,所以在此單獨拿出來講解。
2.4 函數指針數組
還有一種較爲常用的關於函數指針的用法——函數指針數組。假設現在有一個文件處理程序,通過一個菜單按鈕來選擇相應的操作 (打開文件,讀文件,寫文件,關閉文件 )。這些操作都實現爲函數且類型相同,分別爲:
void open( );
void read( );
void write( );
void close( );
現在定義一個函數指針類型的別名
PF: typedef void (*PF) ( );
把以上4種操作取地址放入一個數組中,得到:
PF file_options[ ] = {
&open,
&read,
&write,
&close
};
這個數組中的元素都是指向不接受參數且不返回任何值的函數的指針,因此這是一個函數指針數組。接下來,定義一個函數指針類型的指針 action並初始化爲函數指針數組的第一個元素: PF* action = file_options;,如果不好理解,可以類比一下 int ia[4] = {0, 1, 2, 3}; int *ip = ia;,這裏PF 相當於int,這樣應該比較好懂了。通過對指針 action進行下標操作可以調用數組中的任一操作,如: action[2]( )會調用 write操作,以此類推。在實際中,指針 action可以和鼠標或者其他 GUI對象相關聯,以達到相應的目的。
2.5 複雜的函數指針聲明
2. ANSI C標準將f ( )認爲是(*f)( )的簡寫形式,並且推薦使用f ( )形式,因爲它更符合函數調用的邏輯。
3. 關於函數指針的加減運算沒有意義。
4. 在使用中函數名會被轉換爲指向這個函數的指針,指針的值就是函數的入口地址,函數的地址在編譯期是未知的,而是在鏈接時確定的。
5. 對於複雜的函數指針聲明,可以用右左法則來進行分析。