一、定義函數指針
return_type (*func_pointer)(parameter_list)
普通指針變量的定義
int * p;char * pointer;
類型的限定都在變量前面;
函數指針類型的限定是前后都有,前面是返回類型,后面是輸入參數。
利用typedef 可以簡化上面的表達方式。
typedef return_type (*FunctionPointer) (parameter_list);FunctionPointer func_pointer;
這樣是不是容易讀了,和上面的功能一樣,定義了一個返回類型為return_type ,輸入參數為parameter_list的函數指針。
二、定義返回函數指針的函數
return_type(*function(func_parameter_list))(parameter_list)
方框圈出來的表示返回類型為函數指針,剩下的部分就表示一個function函數,輸入參數為func_parameter_list。
它就等價于 FunctionPointer function(func_parameter_list); 。
再看看:
void ( *signal( int sig, void (* handler)( int )))( int );
signal是一個返回函數指針的函數,signal的輸入為int 變量和一個函數指針。
三、函數指針的使用
#include <stdio.h> int add(int a, int b); void main() { int(*fun1)(int a, int b) = add; int(*fun2)(int a, int b) = &add; int(*fun3)(int a, int b) = *add; printf("%d/n", fun1(1, 2)); printf("%d/n", fun2(1, 2)); printf("%d/n", fun3(1, 2)); char input[10]; gets(input); } int add(int a, int b) { return a + b; }
函數名會被隱式的轉變為指針,前面加*和&操作符都不起作用,printf的結果都是3。
四、神奇的代碼
int (*(*pf())())(){ return nullptr; }
哇哦,這是個什么函數!畫個框框分解它
小框表示返回的是一個函數指針,在圈個大框,又是一個函數指針。
它就表示,pf() 返回的是一個函數指針,這個函數指針對應一個無輸入參數的函數:返回值也是函數指針(對應無輸入參數的函數,返回值為int類型)。好復雜啊,有點暈!
利用typedef 簡化一下。
typedef int(*Fun1) (); typedef Fun1(*Fun2) (); Fun2 pf() { return nullptr; }
這樣看就舒服多了。
五、這又是什么鬼!
(*(void(*) ())0)();
畫個框看看:
小框里代表一個函數指針,常數前面加括號代表類型的強制轉換。咦,它把0強制轉換成了一個函數指針,并執行!這是什么操作?。?br />六、一段驗證代碼
#include <stdio.h> typedef int Function(int, int); typedef int(*FunctionPointer1) (int, int); typedef FunctionPointer1(*FunctionPointer2) (); int fun1(int a, int b) { return a + b; } FunctionPointer1 fun2() { return fun1; } FunctionPointer2 fun3() { return fun2; } int(*(*fun4())())(int, int) { return fun2; } void main() { Function* fuction = fun1; FunctionPointer1 fun = fun1; int a = fun3()()(3, 4); int b = fun4()()(5, 6); printf("%d/n%d/n", a, b); printf("fun1:%d/n*fun1:%d/n&fun1:%d", fun1, *fun1, &fun1); printf("fun:%d/n*fun:%d/n&fun:%d", fun, *fun, &fun); char chars[10]; gets(chars); }
函數名前面加不加*,&操作符,都是一個效果;函數指針前面加不加*操作符是一個效果,但是加上&操作符就代表著取指針的地址了。
可以通過typedef int Function(int, int); 為一種類型的函數定義別名,但是使用的時候只能定義指針形式的變量:
Function* fuction = fun1;
七、一個問題
在stackoverflow上偶爾看到如下的問題,代碼如下
#includevoid hello() { printf("hello"); }int hello_1(){ printf("hello 1"); return 0;} int main(void) { (*****hello)(); (****hello_1)();}
執行結果是無論hello前面有多少個指針符號,都是執行hello()函數,打印“hello”。
為什么出現這樣的結果呢:
用指針指向一個函數是OK的,但是仍然還要被轉化為一個function pointer。其實使用*來指向一個函數 == CALL這個函數。因此無論指向多少次,仍然也是調用這個函數。
為什么一個函數會被轉化成一個指針呢?答案就是將函數默認的轉換成函數指針,可以減少&的使用,編譯器默認的將函數轉化為函數指針,也省得你每次調用函數時加*調用函數。
哈哈,也就是我們之前說的,函數即指針。似乎有點不是很清晰,再看下面的例子
void foo() { printf("Foo to you too!.../n");}; int a = 2;int* test(){ return &a;}int main(){ int i; void (*p1_foo)() = foo; void (*p2_foo)() = *foo; void (*p3_foo)() = &foo; void (*p4_foo)() = *&foo; void (*p5_foo)() = &*foo; void (*p6_foo)() = **foo; void (*p7_foo)() = **********************foo; (*p1_foo)(); (*p2_foo)(); (*p3_foo)(); (*p4_foo)(); (*p5_foo)(); (*p6_foo)(); (*p7_foo)(); i = *(***test)();printf("i=%d/n",i);}
上面的列子不出例外,都能正常打印我們想要的數據。
但是對于&,則要進行仔細的分析一下:
&對于一個函數的操作,是返回一個指針,指向函數的指針,如果在對此指針執行&也就是&&foo,則會返回error,因為&foo是一個指針數值,也就是一個rvalue類型,再對他進行&操作,顯然是返回error的。
&&foo //EROOR&*&*&*&*&*&*foo //OK&******&foo //OK
新聞熱點
疑難解答
圖片精選