C/C++中函式指標的含義

firedragonpzy發表於2012-08-01

函式存放在記憶體的程式碼區域內,它們同樣有地址,我們如何能獲得函式的地址呢?

  如果我們有一個int test(int a)的函式,那麼,它的地址就是函式的名字,這一點如同陣列一樣,陣列的名字就是陣列的起始地址。

  定義一個指向函式的指標用如下的形式,以上面的test()為例:

int (*fp)(int a);//這裡就定義了一個指向函式的指標

  函式指標不能絕對不能指向不同型別,或者是帶不同形參的函式,在定義函式指標的時候我們很容易犯如下的錯誤。

int *fp(int a);//這裡是錯誤的,因為按照結合性和優先順序來看就是先和()結合,然後變成了一個返回整形指標的函式了,而不是函式指標,這一點尤其需要注意!

  下面我們來看一個具體的例子:

#include <iostream>
#include <string>
using namespace std;

int test(int a);

void main(int argc,char* argv[])
{
cout<<test<<endl;//顯示函式地址
int (*fp)(int a);
fp=test;//將函式test的地址賦給函式學指標fp
cout<<fp(5)<<"|"<<(*fp)(10)<<endl;
//上面的輸出fp(5),這是標準c++的寫法,(*fp)(10)這是相容c語言的標準寫法,兩種同意,但注意區分,避免寫的程式產生移植性問題!
cin.get();
}

int test(int a)
{
return a;
}

  typedef定義可以簡化函式指標的定義,在定義一個的時候感覺不出來,但定義多了就知道方便了,上面的程式碼改寫成如下的形式:

#include <iostream>
#include <string>
using namespace std;

int test(int a);

void main(int argc,char* argv[])
{
cout<<test<<endl;
typedef int (*fp)(int a);//注意,這裡不是生命函式指標,而是定義一個函式指標的型別,這個型別是自己定義的,型別名為fp
fp fpi;//這裡利用自己定義的型別名fp定義了一個fpi的函式指標!
fpi=test;
cout<<fpi(5)<<"|"<<(*fpi)(10)<<endl;
cin.get();
}

int test(int a)
{
return a;
}

 函式指標同樣是可以作為引數傳遞給函式的,下面我們看個例子,仔細閱讀你將會發現它的用處,稍加推理可以很方便我們進行一些複雜的程式設計工作。

//-------------------該例以上一個例子作為基礎稍加了修改-----------------------------
#include <iostream>
#include <string>
using namespace std;

int test(int);

int test2(int (*ra)(int),int);

void main(int argc,char* argv[])
{
cout<<test<<endl;
typedef int (*fp)(int);
fp fpi;
fpi=test;//fpi賦予test 函式的記憶體地址

cout<<test2(fpi,1)<<endl;//這裡呼叫test2函式的時候,這裡把fpi所儲存的函式地址(test的函式地址)傳遞了給test2的第一個形參
cin.get();
}

int test(int a)
{
return a-1;
}

int test2(int (*ra)(int),int b)//這裡定義了一個名字為ra的函式指標
{
int c=ra(10)+b;//在呼叫之後,ra已經指向fpi所指向的函式地址即test函式
return c;
}

  利用函式指標,我們可以構成指標陣列,更明確點的說法是構成指向函式的指標陣列,這麼說可能就容易理解的多了。

#include <iostream>
#include <string>
using namespace std;

void t1(){cout<<"test1";}
void t2(){cout<<"test2";}
void t3(){cout<<"test3";}
void main(int argc,char* argv[])
{
void* a[]={t1,t2,t3};
cout<<"比較t1()的記憶體地址和陣列a[0]所儲存的地址是否一致"<<t1<<"|"<<a[0]<<endl;

cout<<a[0]();//錯誤!指標陣列是不能利用陣列下標操作呼叫函式的

typedef void (*fp)();//自定義一個函式指標型別
fp b[]={t1,t2,t3}; //利用自定義型別fp把b[]定義趁一個指向函式的指標陣列
b[0]();//現在利用指向函式的指標陣列進行下標操作就可以進行函式的間接呼叫了;
cin.get();
}

  仔細看上面的例子可能不用我多說大家也會知道是怎麼一會事情了,最後我們做一個重點小結,只要記住這一點,對於理解利用函式指標構成陣列進行函式間接呼叫就很容易了!

void* a[]={t1,t2,t3};
cout<<"比較t1()的記憶體地址和陣列a[0]所儲存的地址是否一致"<<t1<<"|"<<a[0]<<endl;

cout<<a[0]();//錯誤!指標陣列是不能利用陣列下標操作呼叫函式的

  上面的這一小段中的錯誤行,為什麼不能這麼呼叫呢?

  前一篇教程我們已經說的很清楚了,不過在這裡我們還是複習一下概念,指標陣列元素所儲存的只是一個記憶體地址,既然只是個記憶體地址就不可能進行a[0]()這樣地址帶括號的操作,而函式指標不同它是一個例外,函式指標只所以這麼叫它就是因為它是指向函式指向記憶體的程式碼區的指標,它被系統授予允許與()括號操作的權利,進行間接的函式呼叫,既然函式指標允許這麼操作,那麼被定義成函式指標的陣列就一定是可以一樣的操作的。


摘自:[url]http://pcedu.pconline.com.cn/empolder/gj/c/0503/566020_all.html#content_page_1[/url]

相關文章