函數(shù)指針,指針函數(shù),函數(shù)指針數(shù)組

這是一個(gè)群友發(fā)的筆試題目,里面涉及的東西也比較有意思。
直接看代碼
void?(*f[])(char?*)
這個(gè)是個(gè)什么東西?
我們先看看下面的東西
函數(shù)指針和指針函數(shù)的定義
我們看個(gè)代碼
int?*func(int?a,int?b)
我們之前說(shuō)過(guò)運(yùn)算符的優(yōu)先級(jí),「 *?」 ?的優(yōu)先級(jí)低于「( ?」
由于「 * 」的優(yōu)先級(jí)低于「?()?」的優(yōu)先級(jí),因而func首先和后面的「 () 」結(jié)合,也就意味著,func是一個(gè)函數(shù)。即:
int?*(func)(int?a,int?b)
然后這個(gè)函數(shù)的返回值的類型是「? int *?」 即:指向int類型的指針
然后我們這樣修改上面的代碼
int?(*func)(int?a,int?b)
「(*func) 」說(shuō)明func是一個(gè)指針,然后后面跟著「()」說(shuō)明這個(gè)指針指向一個(gè)函數(shù),即指向函數(shù)的指針。
所以
函數(shù)指針:?首先是一個(gè)指針,這個(gè)指針指向一個(gè)函數(shù)
指針函數(shù):首先是一個(gè)函數(shù),這個(gè)函數(shù)的返回值一個(gè)指針
用typedef聲明一個(gè)函數(shù)指針
我們聲明一個(gè)函數(shù)指針,正常方法是
int?(*pfunc)(int?a,int?b)
當(dāng)我們命名很多個(gè)函數(shù)指針的時(shí)候,用上面的方法顯得非常不方便,所以我們可以這樣做
typedef?int?(*PF)?(int?a,intb)
PF?pfunc;
例程:
#include?"stdio.h"
typedef?int(*PF)(int,?int);
int?add(int?a,?int?b)
{
?return?a?+?b;
}
int?reduce(int?a,?int?b)
{
?return?a?-?b;
}
int?main()
{
?PF?pfunc?=?NULL;
?pfunc?=?add;
?printf("add:%d\n",pfunc(3,?4));
?pfunc?=?reduce;
?printf("reduce:%d\n",?pfunc(3,?4));
?/*getchar是用VS編寫方便查看輸出*/
?getchar();
?return?0;
}

再說(shuō)回上面的那個(gè)題目
void?(*f[])(char?*)
f 是個(gè)什么鬼東西了?
[] 的優(yōu)先級(jí) 比 *的優(yōu)先級(jí)高,所以 f首先是修飾了數(shù)組,然后跟后面的 *組合,就說(shuō)明這個(gè)數(shù)組里面住的都是 指針,這些指針是什么呢,再出來(lái)看看就看到了,這個(gè)指針是 一個(gè)函數(shù),這個(gè)函數(shù)的 參數(shù)是 char *返回值是void。
示例代碼
#include?
void?(*f[3])(char?*);
void?efunction(char?*?s)
{
?printf("%s\n",s);
}
int?main()
{
?f[0]?=?efunction;
?//void?(*f[])(char?*)?=?{efunction};?
?(*f[0])("hello?code");
????return?0;
}
代碼輸出
hello?code
--------------------------------
Process?exited?after?0.08441?seconds?with?return?value?0
請(qǐng)按任意鍵繼續(xù).?.?.
函數(shù)指針在項(xiàng)目總的實(shí)際應(yīng)用
這是我的android項(xiàng)目hal部分的代碼,這部分代碼用到的是函數(shù)指針,通過(guò)name來(lái)調(diào)用不同的函數(shù)。

懂了這些,我們就可以看懂別人的代碼了
我們有時(shí)候看別人的代碼時(shí)候,經(jīng)常是一面懵逼,比如下面這個(gè)void (*p)(); 還有這個(gè)(*(void(*) ())0)();
我記得我在以前的文章里面有談到一個(gè)右左原則,從p開始看,往右走直到遇到)再往左走遇到(,(*p)我們就可以看出p是一個(gè)指針,繼續(xù)分析往右走,遇到(),說(shuō)明p指向一個(gè)(void)的函數(shù),往左走,知道p指向的函數(shù)返回值是void。
ok,看下面的例子。
#include?"stdio.h"
void?Function()
{
????printf("Call????Function!\n");
}
int?main()
{
????void(*p)();
????*(int*)&p?=?(int)Function;
????(*p)();
????getchar();
????return?0;
}

然后繼續(xù)分析(*(void(*) ())0)();
1、 void (*)()?我們上面分析了這個(gè)是一個(gè)函數(shù)指針,只是把p去掉了而已。2、把上面的 void (*)()用PN代替,上面的表達(dá)式變成(*(PN)0)();PN后面有一個(gè)0,這個(gè)是讓我們咋舌的地方,然后我們向一下(char)a;這樣的表達(dá)式,所以*(PN)0就是把0當(dāng)成一個(gè)地址,強(qiáng)制轉(zhuǎn)換為PN類型,用*這個(gè)鑰匙取出這個(gè)地址區(qū)域的值。3、把 (*(PN)0)()替換成PM,原來(lái)的表達(dá)式變成PM(),這樣大家看起來(lái)比較容易了吧,就是正常的函數(shù)調(diào)用。
給個(gè)例子自己去參透一下
#include?
#include?
char?*?fun1(char?*?p)
{
????printf("%s\n",?p);
????return?p;
}
char?*?fun2(char?*?p)
{
????printf("%s\n",?p);
????return?p;
}
char?*?fun3(char?*?p)
{
????printf("%s\n",?p);
????return?p;
}
int?main()
{
????char?*?(*pf[3])(char?*?p);
????pf[0]?=?fun1;?//?可以直接用函數(shù)名
????pf[1]?=?&fun2;?//?可以用函數(shù)名加上取地址符
????pf[2]?=?&fun3;
????pf[0]("fun1");
????pf[0]("fun2");
????pf[0]("fun3");
????getchar();
????return?0;
}

