c語言函數指針的理解與使用

1.函數指針的定義數組


  顧名思義,函數指針就是函數的指針。它是一個指針,指向一個函數。看例子:函數

1spa

2設計

3指針

A) char * (*fun1)(char * p1,char * p2);code

B) char * *fun2(char * p1,char * p2);blog

C) char * fun3(char * p1,char * p2);接口

  

看看上面三個表達式分別是什麼意思?內存


C)這很容易,fun3是函數名,p1,p2是參數,其類型爲char *型,函數的返回值爲char *類型。
B) 也很簡單,與C)表達式相比,惟一不一樣的就是函數的返回值類型爲char**,是個二級指針。
A) fun1是函數名嗎?回憶一下前面講解數組指針時的情形。咱們說數組指針這麼定義或許更清晰:ci

1

int (*)[10] p;

再看看A)表達式與這裏何其類似!明白了吧。這裏fun1不是什麼函數名,而是一個指針變量,它指向一個函數。這個函數有兩個指針類型的參數,函數的返回值也是一個指針。一樣,咱們把這個表達式改寫一下:

1

char * (*)(char * p1,char * p2) fun1;

這樣子是否是好看一些呢?只惋惜編譯器不這麼想。^_^。

 

2.函數指針使用的例子


  上面咱們定義了一個函數指針,但如何來使用它呢?先看以下例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

#include <stdio.h>

#include <string.h>

 

char * fun(char * p1,char * p2)

{

  int i = 0;

  i = strcmp(p1,p2);

 

  if (0 == i)

  {

    return p1;

  }

  else

  {

    return p2;

  }

}

 

int main()

{

  char * (*pf)(char * p1,char * p2);

  pf = &fun;

  (*pf) ("aa","bb");

  return 0;

}

  咱們使用指針的時候,須要經過鑰匙(「*」)來取其指向的內存裏面的值,函數指針使用也如此。經過用(*pf)取出存在這個地址上的函數,而後調用它。

  這裏須要注意到是,在Visual C++6.0裏,給函數指針賦值時,能夠用&fun或直接用函數名fun。這是由於函數名被編譯以後其實就是一個地址,因此這裏兩種用法沒有本質的差異。這個例子很簡單,就再也不詳細討論了。

 

3.*(int*)&p ----這是什麼?


  也許上面的例子過於簡單,咱們看看下面的例子:

1

2

3

4

5

6

7

8

9

10

11

void Function()

{

  printf("Call Function!\n");

}<br>

int main()

{

  void (*p)();

  *(int*)&p=(int)Function;

  (*p)();

  return 0;

} 


這是在幹什麼?*(int*)&p=(int)Function;表示什麼意思?
別急,先看這行代碼:

1

void (*p)();

這行代碼定義了一個指針變量p,p指向一個函數,這個函數的參數和返回值都是void。
&p是求指針變量p自己的地址,這是一個32位的二進制常數(32位系統)。
(int*)&p表示將地址強制轉換成指向int類型數據的指針。
(int)Function表示將函數的入口地址強制轉換成int類型的數據。
分析到這裏,相信你已經明白*(int*)&p=(int)Function;表示將函數的入口地址賦值給指針變量p。


那麼(*p) ();就是表示對函數的調用。


講解到這裏,相信你已經明白了。其實函數指針與普通指針沒什麼差異,只是指向的內容不一樣而已。
使用函數指針的好處在於,能夠將實現同一功能的多個模塊統一塊兒來標識,這樣一來更容易後期的維護,系統結構更加清晰。或者概括爲:便於分層設計、利於系統抽象、下降耦合度以及使接口與實現分開。

 

 

4.(*(void(*) ())0)()------這是什麼?


  是否是感受上面的例子太簡單,不夠刺激?好,那就來點刺激的,看下面這個例子:

1

(*(void(*) ())0)();

這是《C Traps and Pitfalls》這本經典的書中的一個例子。沒有發狂吧?下面咱們就來分析分析:

1

2

3

4

第一步:void(*) (),能夠明白這是一個函數指針類型。這個函數沒有參數,沒有返回值。

第二步:(void(*) ())0,這是將0強制轉換爲函數指針類型,0是一個地址,也就是說一個函數存在首地址爲0的一段區域內。

第三步:(*(void(*) ())0),這是取0地址開始的一段內存裏面的內容,其內容就是保存在首地址爲0的一段區域內的函數。

第四步:(*(void(*) ())0)(),這是函數調用。


好像仍是很簡單是吧,上面的例子再改寫改寫:

1

(*(char**(*) (char **,char **))0) ( char **,char **);


若是沒有上面的分析,肯怕不容易把這個表達式看明白吧。不過如今應該是很簡單的一件事了。讀者覺得呢?

 

5.函數指針數組

 

  如今咱們清楚表達式

1

char * (*pf)(char * p);

定義的是一個函數指針pf。既然pf是一個指針,那就能夠儲存在一個數組裏。把上式修改一下:

1

char * (*pf[3])(char * p);

這是定義一個函數指針數組。

 

  它是一個數組,數組名爲pf,數組內存儲了3個指向函數的指針。這些指針指向一些返回值類型爲指向字符的指針、參數爲一個指向字符的指針的函數。

  這念起來彷佛有點拗口。不過沒關係,關鍵是你明白這是一個指針數組,是數組。函數指針數組怎麼使用呢?這裏也給出一個很是簡單的例子,只要真正掌握了使用方法,再複雜的問題均可以應對。

 

以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

#include <stdio.h>

#include <string.h>

<br>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;

}

<br>int main()

{

  char * (*pf[3])(char * p);

  pf[0] = fun1; //能夠直接用函數名

  pf[1] = &fun2; //能夠用函數名加上取地址符

  pf[2] = &fun3;<br>

  pf[0]("fun1");

  pf[0]("fun2");

  pf[0]("fun3");

  return 0;

} 

 

6.函數指針數組的指針


  看着這個標題沒發狂吧?函數指針就夠通常初學者折騰了,函數指針數組就更加麻煩,如今的函數指針數組指針就更難理解了。
其實,沒這麼複雜。前面詳細討論過數組指針的問題,這裏的函數指針數組指針不就是一個指針嘛。只不過這個指針指向一個數組,這個數組裏面存的都是指向函數的指針。僅此而已。


下面就定義一個簡單的函數指針數組指針:

1

char * (*(*pf)[3])(char * p);


注意,這裏的pf和上一節的pf就徹底是兩碼事了。上一節的pf並不是指針,而是一個數組名;這裏的pf確實是實實在在的指針。這個指針指向一個包含了3個元素的數組;這個數字裏面存的是指向函數的指針;這些指針指向一些返回值類型爲指向字符的指針、參數爲一個指向字符的指針的函數。

  這比上一節的函數指針數組更拗口。其實你不用管這麼多,明白這是一個指針就ok了。其用法與前面講的數組指針沒有差異。下面列一個簡單的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

#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 * (*a[3])(char * p);

    char * (*(*pf)[3])(char * p);

    pf = &a;

 

    a[0] = fun1;

    a[1] = &fun2;

    a[2] = &fun3;

 

    pf[0][0]("fun1");

    pf[0][1]("fun2");

    pf[0][2]("fun3");

    return 0;

}

  

 

 

 

 

 

 

 

 

 

 

 

參考:陳正衝老師的《c語言深度剖析》。


 

做者:木木

出處:http://haore147.cnblogs.com/

博客文章大部分爲原創,版權歸做者和博客園共有,歡迎轉載。

相關文章
相關標籤/搜索