函數(shù)指針,指針函數(shù),函數(shù)指針數(shù)組
這是一個群友發(fā)的筆試題目,里面涉及的東西也比較有意思。
直接看代碼
void (*f[])(char *)
這個是個什么東西?
我們先看看下面的東西
函數(shù)指針和指針函數(shù)的定義
我們看個代碼
int *func(int a,int b)
我們之前說過運算符的優(yōu)先級,「 * 」 的優(yōu)先級低于「( 」
由于「 * 」的優(yōu)先級低于「 () 」的優(yōu)先級,因而func首先和后面的「 () 」結(jié)合,也就意味著,func是一個函數(shù)。即:
int *(func)(int a,int b)
然后這個函數(shù)的返回值的類型是「 int * 」 即:指向int類型的指針
然后我們這樣修改上面的代碼
int (*func)(int a,int b)
「(*func) 」說明func是一個指針,然后后面跟著「()」說明這個指針指向一個函數(shù),即指向函數(shù)的指針。
所以
函數(shù)指針: 首先是一個指針,這個指針指向一個函數(shù)
指針函數(shù):首先是一個函數(shù),這個函數(shù)的返回值一個指針
用typedef聲明一個函數(shù)指針
我們聲明一個函數(shù)指針,正常方法是
int (*pfunc)(int a,int b)
當我們命名很多個函數(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;
}
再說回上面的那個題目
void (*f[])(char *)
f
是個什么鬼東西了?
[]
的優(yōu)先級 比 *
的優(yōu)先級高,所以 f
首先是修飾了數(shù)組,然后跟后面的 *
組合,就說明這個數(shù)組里面住的都是 指針,這些指針是什么呢,再出來看看就看到了,這個指針是 一個函數(shù),這個函數(shù)的 參數(shù)是 char *
返回值是void
。
示例代碼
#include <stdio.h>
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
請按任意鍵繼續(xù). . .
函數(shù)指針在項目總的實際應用
這是我的android項目hal部分的代碼,這部分代碼用到的是函數(shù)指針,通過name來調(diào)用不同的函數(shù)。
懂了這些,我們就可以看懂別人的代碼了
我們有時候看別人的代碼時候,經(jīng)常是一面懵逼,比如下面這個void (*p)();
還有這個(*(void(*) ())0)();
我記得我在以前的文章里面有談到一個右左原則,從p
開始看,往右走直到遇到)再往左走遇到(
,(*p)
我們就可以看出p
是一個指針,繼續(xù)分析往右走,遇到()
,說明p
指向一個(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 (*)()
我們上面分析了這個是一個函數(shù)指針,只是把p
去掉了而已。 -
2、把上面的 void (*)()
用PN
代替,上面的表達式變成(*(PN)0)()
;PN
后面有一個0
,這個是讓我們咋舌的地方,然后我們向一下(char)a
;這樣的表達式,所以*(PN)0
就是把0
當成一個地址,強制轉(zhuǎn)換為PN類型,用*
這個鑰匙取出這個地址區(qū)域的值。 -
3、把 (*(PN)0)()
替換成PM
,原來的表達式變成PM()
,這樣大家看起來比較容易了吧,就是正常的函數(shù)調(diào)用。
給個例子自己去參透一下
#include <stdio.h>
#include <string.h>
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;
}
免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!