標籤:
函數指標是指向函數的指標變數。 因而“函數指標”本身首先應是指標變數,只不過該指標變數指向函數。這正如用指標變數可指向整型變數、字元型、數組一樣,這裡是指向函數。如前所述,C在編譯時間,每一個函數都有一個入口地址,該入口地址就是函數指標所指向的地址。有了指向函數的指標變數後,可用該指標變數調用函數,就如同用指標變數可引用其他類型變數一樣,在這些概念上是大體一致的。函數指標有兩個用途:調用函數和做函數的參數。
1方法函數指標的聲明方法為:傳回值類型 ( * 指標變數名) ([形參列表]);注1:“傳回值類型”說明函數的傳回型別,“(指標變數名 )”中的括弧不能省,括弧改變了運算子的優先順序。若省略整體則成為一個函數說明,說明了一個返回的資料類型是指標的函數,後面的“形參列表”表示指標變數指向的函數所帶的參數列表。例如:int func(int x); /* 聲明一個函數 */int (*f) (int x); /* 聲明一個函數指標 */f=func; /* 將func函數的首地址賦給指標f */或者使用下面的方法將函數地址賦給函數指標:f = &func;賦值時函數func不帶括弧,也不帶參數,由於func代表函數的首地址,因此經過賦值以後,指標f就指向函數func(x)的代碼的首地址。注2:函數括弧中的形參可有可無,視情況而定。下面的程式說明了函數指標調用函數的方法:例一、
#include<stdio.h>int max(int x,int y){return (x>y? x:y);}int main(){ int (*ptr)(int, int); int a, b, c; ptr = max; scanf("%d%d", &a, &b); c = (*ptr)(a,b); printf("a=%d, b=%d, max=%d", a, b, c); return 0;}
ptr是指向函數的指標變數,所以可把函數max()賦給ptr作為ptr的值,即把max()的入口地址賦給ptr,以後就可以用ptr來調用該函數,實際上ptr和max都指向同一個入口地址,不同就是ptr是一個指標變數,不像函數名稱那樣是死的,它可以指向任何函數,就看你想怎麼做了。在程式中把哪個函數的地址賦給它,它就指向哪個函數。而後用指標變數調用它,因此可以先後指向不同的函數。不過注意,指向函數的指標變數沒有++和--運算,用時要小心。不過,在某些編譯器中這是不能通過的。這個例子的補充如下。應該是這樣的:1.定義函數指標類型:typedef int (*fun_ptr)(int,int);2.聲明變數,賦值:fun_ptr max_func=max;也就是說,賦給函數指標的函數應該和函數指標所指的函數原型是一致的。例二、
#include<stdio.h>void FileFunc(){ printf("FileFunc\n");}void EditFunc(){ printf("EditFunc\n");}void main(){ typedef void(*funcp)(); funcp pfun=FileFunc; pfun(); pfun=EditFunc; pfun();}
2對比區別指標函數和函數指標的區別:1,這兩個概念都是簡稱,指標函數是指傳回值是指標的函數,即本質是一個函數。我們知道函數都有傳回型別(如果不傳回值,則為無值型),只不過指標函數傳回型別是某一類型的指標。其定義格式如下所示:傳回型別標識符*函數名稱(形式參數表){函數體}傳回型別可以是任何基本類型和複合類型。返回指標的函數的用途十分廣泛。事實上,每一個函數,即使它不帶有返回某種類型的指標,它本身都有一個入口地址,該地址相當於一個指標。比如函數返回一個整型值,實際上也相當於返回一個指標變數的值,不過這時的變數是函數本身而已,而整個函數相當於一個“變數”。例如下面一個返回指標函數的例子:
//指標函數是指傳回值是指標的函數,即本質是一個函數:#include<iostream>using namespace std;int main(){ float*find(float(*p)[4],intm);//查詢序號為m的學生的四門課程的成績 float score[][4]={{50,51,52,55},{70,70,40,80}, {77,99,88,67}};//定義成績數組,第一維可以為變數 float*pf=NULL;//定義一個指標時一定要初始化 int i,m; cout<<"請輸入您想查詢的學生的序號:"; cin>>m; pf=find(score,m);//返回為一維數組指標,指向一個學產生績 for(i=0;i<4;i++) cout<<*(pf+i)<<""; cout<<endl; return 0;}float *find(float(*p)[4],intm){ float *pf=NULL; pf=*(p+m);//p是指向二維數組的指標,加*取一維數組的指標 return pf;}
學生學號從0號算起,函數find()被定義為指標函數,其形參pointer是指標指向包含4個元素的一維數組的指標變數。pf是一個指標變數,它指向浮點型變數。main()函數中調用find()函數,將score數組的首地址傳給pointer.
3指標數組定義關於函數指標數組的定義方法,有兩種:一種是標準的方法;一種是矇騙法。第一種,標準方法:{分析:函數指標數組是一個其元素是函數指標的數組。那麼也就是說,此資料結構是一個數組,且其元素是一個指向函數入口地址的指標。根據分析:首先說明是一個數組:數組名[]其次,要說明其元素的資料類型指標:*數組名[].再次,要明確這每一個數組元素是指向函數入口地址的指標:函數傳回值類型 (*數組名[])().請注意,這裡為什麼要把“*數組名[]”用括弧擴起來呢?因為圓括弧和數組說明符的優先順序是等同的,如果不用圓括弧把指標數組說明運算式擴起來,根據圓括弧和方括弧的結合方向,那麼 *數組名[]() 說明的是什麼呢?是元素傳回值類型為指標的函數數組。有這樣的函數數組嗎?不知道。所以必須括起來,以保證數組的每一個元素是指標。}第二種,矇騙法:儘管函數不是變數,但它在記憶體中仍有其物理地址,該地址能夠賦給指標變數。擷取函數地址的方法是:用不帶有括弧和參數的函數名得到。函數名相當於一個指向其函數入口指標常量。 那麼既然函數名是一個指標常量,那麼就可以對其進行一些相應的處理,如強制類型轉換。那麼我們就可以把這個地址放在一個整形指標數組中,然後作為函數指標調用即可。完整例子:
#include <stdio.h> int add1(int a1,int b1);int add2(int a2,int b2); int main(void){ int numa1 = 1, numb1 = 2; int numa2 = 2, numb2 = 3; int(*op[2])(int a,int b); op[0] = add1; op[1] = add2; printf("%d%d\n", op[0](numa1, numb1), op[1](numa2, numb2));} int add1(int a1,int b1){ return a1 + b1;} int add2(int a2,int b2){ return a2 + b2;}
賦值為函數指標數組賦值有兩種方式:靜態定義和動態賦值。1. 靜態定義在定義函數指標數組的時候,已經確定了每個成員所對應的函數。例如:1void(*Array[])(void)={Stop,Run,Jump};從根本上講函數指標數組依然是數組,所以和數組的定義類似,由於是靜態賦值,[ ]裡面的數字可以省略。這個函數指標數組的成員有三個。1 Array[1]();//執行Run函數2. 動態賦值也可以先定義一個函數指標數組,在需要的時候為其賦值。為了還原其本來面目,我們先對這個執行特定類型的函數指標進行類型重定義,然後再用這個新資料類型來定義數組。如下:
typedef void(*iFunc)(void);//此類型的函數指標指向的是無參、無傳回值的函數。Funcint Array[32];//定義一個函數指標數組,其每個成員為INTFUN類型的函數指標Array[10]=INT_TIMER0;//為其賦值Array[10]();//調用函數指標數組的第11個成員指向的函數
C 函數指標