程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深刻解析C說話中函數指針的界說與應用

深刻解析C說話中函數指針的界說與應用

編輯:關於C++

深刻解析C說話中函數指針的界說與應用。本站提示廣大學習愛好者:(深刻解析C說話中函數指針的界說與應用)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C說話中函數指針的界說與應用正文


1.函數指針的界說  
  函數是由履行語句構成的指令序列或許代碼,這些代碼的有序聚集依據其年夜小被分派到必定的內存空間中,這一片內存空間的肇端地址就成為函數的地址,分歧的函數有分歧的函數地址,編譯器經由過程函數名來索引函數的進口地址,為了便利操作類型屬性雷同的函數,c/c++引入了函數指針,函數指針就是指向代碼進口地址的指針,是指向函數的指針變量。 因此“函數指針”自己起首應當是指針變量,只不外該指針變量指向函數。這正如用指針變量可指向整形變量、字符型、數組一樣,這裡是指向函數。C在編譯時,每個函數都有一個進口地址,該進口地址就是函數指針所指向的地址。有了指向函數的指針變量後,可用該指針變量挪用函數,就好像用指針變量可援用其他類型變量一樣,在這些概念上是分歧的。函數指針有兩個用處:挪用函數和做函數的參數。

函數指針的聲明辦法為:

數據類型標記符 (指針變量名) (形參列表);

“函數類型”解釋函數的前往類型,因為“()”的優先級高於“*”,所以指針變量名外的括號必弗成少,前面的“形參列表”表現指針變量指向的函數所帶的參數列表。例如:

  int function(int x,int y); /* 聲明一個函數 */

  int (*f) (int x,int y); /* 聲明一個函數指針 */

  f=function; /* 將function函數的首地址賦給指針f */

  賦值時函數function不帶括號,也不帶參數,因為function代表函數的首地址,是以經由賦值今後,指針f就指向函數function(int x,int y);的代碼的首地址。

2.函數指針應用的例子 
曉得了若何界說一個函數指針,但若何來應用它呢?先看以下例子:

#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 ----這是甚麼?

  或許下面的例子過於簡略,我們看看上面的例子:

void Function()
{
  printf("Call Function!\n");
}<br>
int main()
{
  void (*p)();
  *(int*)&p=(int)Function;
  (*p)();
  return 0;
} 

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

void (*p)();

這行代碼界說了一個指針變量p,p指向一個函數,這個函數的參數和前往值都是void。
&p是求指針變量p自己的地址,這是一個32位的二進制常數(32位體系)。
(int*)&p表現將地址強迫轉換成指向int類型數據的指針。
(int)Function表現將函數的進口地址強迫轉換成int類型的數據。
剖析到這裡,信任你曾經明確*(int*)&p=(int)Function;表現將函數的進口地址賦值給指針變量p。


那末(*p) ();就是表現對函數的挪用。


講授到這裡,信任你曾經明確了。其實函數指針與通俗指針沒甚麼差異,只是指向的內容分歧罷了。
應用函數指針的利益在於,可以將完成統一功效的多個模塊同一起來標識,如許一來更輕易前期的保護,體系構造加倍清楚。或許歸結為:便於分層設計、利於體系籠統、下降耦合度和使接口與完成離開。

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

是否是感到下面的例子太簡略,不敷安慰?好,那就來點安慰的,看上面這個例子:

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

這是《C Traps and Pitfalls》這本經典的書中的一個例子。沒有發瘋吧?上面我們就來剖析剖析:

第一步:void(*) (),可以明確這是一個函數指針類型。這個函數沒有參數,沒有前往值。
第二步:(void(*) ())0,這是將0強迫轉換為函數指針類型,0是一個地址,也就是說一個函數存在首地址為0的一段區域內。
第三步:(*(void(*) ())0),這是取0地址開端的一段內存外面的內容,其內容就是保留在首地址為0的一段區域內的函數。
第四步:(*(void(*) ())0)(),這是函數挪用。

似乎照樣很簡略是吧,下面的例子再改寫改寫:

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

假如沒有下面的剖析,肯怕不輕易把這個表達式看明確吧。不外如今應當是很簡略的一件事了。讀者認為呢?

5.函數指針數組

如今我們清晰表達式

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

界說的是一個函數指針pf。既然pf是一個指針,那便可以貯存在一個數組裡。把上式修正一下:

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

這是界說一個函數指針數組。

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

這念起來仿佛有點拗口。不外沒關系,症結是你明確這是一個指針數組,是數組。函數指針數組怎樣應用呢?這裡也給出一個異常簡略的例子,只需真正控制了應用辦法,再龐雜的成績都可以應對。

以下:

#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.函數指針數組的指針


  看著這個題目沒發瘋吧?函數指針就夠普通初學者折騰了,函數指針數組就加倍費事,如今的函數指針數組指針就更難懂得了。
其實,沒這麼龐雜。後面具體評論辯論過數組指針的成績,這裡的函數指針數組指針不就是一個指針嘛。只不外這個指針指向一個數組,這個數組外面存的都是指向函數的指針。僅此罷了。


上面就界說一個簡略的函數指針數組指針:

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

留意,這裡的pf和上一節的pf就完整是兩回事了。上一節的pf並不是指針,而是一個數組名;這裡的pf確切是實其實在的指針。這個指針指向一個包括了3個元素的數組;這個數字外面存的是指向函數的指針;這些指針指向一些前往值類型為指向字符的指針、參數為一個指向字符的指針的函數。

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

#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;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved