(C/C++學習)16.函數指針
阿新 • • 發佈:2018-10-26
代碼段 調用函數 i++ ret 指針 本質 fff class 問題
說明:函數指針,顧名思義就是指向函數的指針。C/C++中函數名的本質其實就是一段代碼段空間的首地址。
1.定義
如下的 pf 就是一個函數指針,指向所有返回類型為 int,並帶有兩個 const int 參數的函數。需要註意的是 *pf 兩邊的括號不能少,否則面定義就變成了聲明了一個函數 pf,其返回類型為 int *, 帶有兩個 const int 參數。
1 int (*pf)(const int, const int);
2.取別名
如果每次都像上面那樣來聲明一個函數,那樣就顯得太復雜了,我們可以通過取別名的方式來簡化聲明復雜程度,如下:
1 typedef int (*cmpFun)(constint, const int);
這樣,cmpFun 就成了一種數據類型,可以用它來聲明和定義形如上面 pf 那樣的函數指針,比如:
1 cmpFun pf = someFunction; 2 cmpFun pf = &someFunction;
下面是一個測試代碼:
1 #include <stdio.h> 2 3 void myCmp(int a,int b) 4 { 5 printf("%d\t%d\n",a,b); 6 } 7 8 typedef void (*PF)(int a, int b); 9PF pf = myCmp; 10 11 int main(void) 12 { 13 (*pf)(1,2); 14 pf(1,2); 15 //兩種訪問方式都沒問題 16 return 0; 17 }
3.函數名作為地址的用法
上面提到了,函數名的本質是一個地址,那如果我們拿到這個地址,是否可以直接調用相應的函數呢?答案是肯定的!如下代碼,先打印出函數名所代表的地址,然後將其強轉成 PF 函數指針類型,然後在對其進行函數的調用。
1 #include <stdio.h> 2 3 void myCmp(int a,intb) 4 { 5 printf("%d\t%d\n",a,b); 6 } 7 8 typedef void (*PF)(int a, int b); 9 PF pf = myCmp; 10 11 int main(void) 12 { 13 pf(1,2); 14 printf("%p\t%p\n",myCmp,&myCmp); 15 ((PF)(0x00401610))(1,2); 16 return 0; 17 }
上面代碼的打印結果為:
1 1 2 2 00401610 00401610 3 1 2
4.回調函數
當函數作為參數而發起的調用函數的過程,就叫作函數的回調。函數的回調企事業是利用了函數指針這一概念。下面是一個回調示例:
1 #include <stdio.h> 2 3 void myCmp(int a,int b) 4 { 5 printf("%d\t%d\n",a,b); 6 } 7 void prin(void (*p)(int a,int b)) 8 { 9 p(1,2); 10 } 11 12 int main(void) 13 { 14 prin(myCmp); 15 return 0; 16 }
5.函數指針數組
如下定義一個返回值和參數皆為 void 的函數指針數組:
1 void (*funcArray[N])(void);
函數指針的一個用法出現在菜單驅動系統中。例如程序可以提示用戶輸入一個整數值來選擇菜單中的一個選項。用戶的選擇可以做函數指針數組的下標,而數組中的指針可以用來調用函數。下面是一個程序示例:
1 #include <stdio.h> 2 void func1() 3 { 4 printf("void func1()\n"); 5 } 6 void func2() 7 { 8 printf("void func2()\n"); 9 } 10 void func3() 11 { 12 printf("void func3()\n"); 13 } 14 15 int main(void) 16 { 17 int i = 0; 18 void (*p[3])(void) = {func1,func2,func3}; 19 for(;i<3;i++) 20 (p[i])(); 21 return 0; 22 } 23 24
6.拓展
1 (*(void(*) ()) 0)()
思考以上代碼的意義!
(C/C++學習)16.函數指針