C語(yǔ)言中的函數(shù)指針學(xué)習(xí)筆記
一、定義函數(shù)指針
return_type (*func_pointer)(parameter_list)
普通指針變量的定義
int * p; char * pointer;
類(lèi)型的限定都在變量前面;
函數(shù)指針類(lèi)型的限定是前后都有,前面是返回類(lèi)型,后面是輸入?yún)?shù)。

利用typedef 可以簡(jiǎn)化上面的表達(dá)方式。
typedef return_type (*FunctionPointer) (parameter_list); FunctionPointer func_pointer;
這樣是不是容易讀了,和上面的功能一樣,定義了一個(gè)返回類(lèi)型為return_type ,輸入?yún)?shù)為parameter_list的函數(shù)指針。
二、定義返回函數(shù)指針的函數(shù)
return_type(*function(func_parameter_list))(parameter_list)

方框圈出來(lái)的表示返回類(lèi)型為函數(shù)指針,剩下的部分就表示一個(gè)function函數(shù),輸入?yún)?shù)為func_parameter_list。
它就等價(jià)于 FunctionPointer function(func_parameter_list); 。
再看看:
void ( *signal( int sig, void (* handler)( int )))( int );

signal是一個(gè)返回函數(shù)指針的函數(shù),signal的輸入為int 變量和一個(gè)函數(shù)指針。
三、函數(shù)指針的使用
#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;
}
函數(shù)名會(huì)被隱式的轉(zhuǎn)變?yōu)橹羔?,前面?和&操作符都不起作用,printf的結(jié)果都是3。
四、神奇的代碼
int (*(*pf())())()
{ return nullptr; }
哇哦,這是個(gè)什么函數(shù)!畫(huà)個(gè)框框分解它

小框表示返回的是一個(gè)函數(shù)指針,在圈個(gè)大框,又是一個(gè)函數(shù)指針。
它就表示,pf() 返回的是一個(gè)函數(shù)指針,這個(gè)函數(shù)指針對(duì)應(yīng)一個(gè)無(wú)輸入?yún)?shù)的函數(shù):返回值也是函數(shù)指針(對(duì)應(yīng)無(wú)輸入?yún)?shù)的函數(shù),返回值為int類(lèi)型)。好復(fù)雜啊,有點(diǎn)暈!
利用typedef 簡(jiǎn)化一下。
typedef int(*Fun1) ();
typedef Fun1(*Fun2) ();
Fun2 pf()
{
return nullptr;
}
這樣看就舒服多了。
五、這又是什么鬼!
(*(void(*) ())0)();
畫(huà)個(gè)框看看:

小框里代表一個(gè)函數(shù)指針,常數(shù)前面加括號(hào)代表類(lèi)型的強(qiáng)制轉(zhuǎn)換。咦,它把0強(qiáng)制轉(zhuǎn)換成了一個(gè)函數(shù)指針,并執(zhí)行!這是什么操作??!
六、一段驗(yàn)證代碼
#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);
}
函數(shù)名前面加不加*,&操作符,都是一個(gè)效果;函數(shù)指針前面加不加*操作符是一個(gè)效果,但是加上&操作符就代表著取指針的地址了。
可以通過(guò)typedef int Function(int, int); 為一種類(lèi)型的函數(shù)定義別名,但是使用的時(shí)候只能定義指針形式的變量:
Function* fuction = fun1;
七、一個(gè)問(wèn)題
在stackoverflow上偶爾看到如下的問(wèn)題,代碼如下
#include
void hello() { printf("hello"); }
int hello_1()
{
printf("hello 1");
return 0;
}
int main(void) {
(*****hello)();
(****hello_1)();
}
執(zhí)行結(jié)果是無(wú)論hello前面有多少個(gè)指針?lè)?hào),都是執(zhí)行hello()函數(shù),打印“hello”。
為什么出現(xiàn)這樣的結(jié)果呢:
用指針指向一個(gè)函數(shù)是OK的,但是仍然還要被轉(zhuǎn)化為一個(gè)function pointer。其實(shí)使用*來(lái)指向一個(gè)函數(shù) == CALL這個(gè)函數(shù)。因此無(wú)論指向多少次,仍然也是調(diào)用這個(gè)函數(shù)。
為什么一個(gè)函數(shù)會(huì)被轉(zhuǎn)化成一個(gè)指針呢?答案就是將函數(shù)默認(rèn)的轉(zhuǎn)換成函數(shù)指針,可以減少&的使用,編譯器默認(rèn)的將函數(shù)轉(zhuǎn)化為函數(shù)指針,也省得你每次調(diào)用函數(shù)時(shí)加*調(diào)用函數(shù)。
哈哈,也就是我們之前說(shuō)的,函數(shù)即指針。似乎有點(diǎn)不是很清晰,再看下面的例子
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);
}
上面的列子不出例外,都能正常打印我們想要的數(shù)據(jù)。
但是對(duì)于&,則要進(jìn)行仔細(xì)的分析一下:
&對(duì)于一個(gè)函數(shù)的操作,是返回一個(gè)指針,指向函數(shù)的指針,如果在對(duì)此指針執(zhí)行&也就是&&foo,則會(huì)返回error,因?yàn)?amp;foo是一個(gè)指針數(shù)值,也就是一個(gè)rvalue類(lèi)型,再對(duì)他進(jìn)行&操作,顯然是返回error的。
&&foo //EROOR &*&*&*&*&*&*foo //OK &******&foo //OK
相關(guān)文章
C++/Php/Python/Shell 程序按行讀取文件或者控制臺(tái)的實(shí)現(xiàn)
下面小編就為大家?guī)?lái)一篇C++/Php/Python/Shell 程序按行讀取文件或者控制臺(tái)的實(shí)現(xiàn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
VC++ 使用 _access函數(shù)判斷文件或文件夾是否存在
這篇文章主要介紹了VC++ 使用 _access函數(shù)判斷文件或文件夾是否存在的相關(guān)資料,需要的朋友可以參考下2015-10-10
opencv實(shí)現(xiàn)圖像顏色空間轉(zhuǎn)換
這篇文章主要為大家詳細(xì)介紹了opencv實(shí)現(xiàn)圖像顏色空間轉(zhuǎn)換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08
C語(yǔ)言編程中統(tǒng)計(jì)輸入的行數(shù)以及單詞個(gè)數(shù)的方法
這篇文章主要介紹了C語(yǔ)言編程中統(tǒng)計(jì)輸入的行數(shù)以及單詞個(gè)數(shù)的方法,利用最基礎(chǔ)的循環(huán)和判斷語(yǔ)句寫(xiě)成,需要的朋友可以參考下2015-11-11

