1樓:匿名使用者
一、定義一個函式指標的方法如下:
返回值型別 (* 指標變數名)([形參列表]);
1、int func(int x); /* 宣告一個函式 */2、int (*f) (int x); /* 宣告一個函式指標 */3、f=func; /* 將func函式的首地址賦給指標f */二、函式指標的用法:
函式指標的應用:(*指標變數名)(引數列表)如:int c=(*ptr)(a,b);/* 函式指標 的使用*/在c語言中,函式本身不是變數,但是可以定義指向函式的指標,也稱作函式指標,函式指標指向函式的入口地址。
這種型別的指標可以被賦值、存放在陣列中、傳遞給函式以及作為函式的返回值等等。
2樓:許詩文
(一) 用函式指標變數呼叫函式
可以用指標變數
指向整形變數、字串、陣列、結構體、也可以指向一個函式。一個函式在編譯時被分配一個入口地址。這個入口地址就稱為函式指標。
可以用一個指標變數指向函式,然後通過該指標變數呼叫此函式。用簡單的數值比較為例:
1 #include
2 #include
3 4 int main()
5 15
16 int max(int x,int y)
17 main函式中的" c = max(a,b); " 包括了一次函式的呼叫。每一個函式都佔用一段記憶體單元。因此,可以用一個指標變數指向一個函式,通過指標變數來訪問它指向的函式。
第7行:int (*p)( int,int ); 用來定義 p 是一個指向函式的指標變數,該函式有兩個整形引數,函式值為整形。注意 *p 兩側的括號不可省略,表示 p 先與 * 結合,是指標變數,然後再與後面的 ( ) 結合,表示此指標變數指向函式,這個函式值 (即函式的返回值) 是整形的。
如果寫成 int *p ( int,int ) ,由於( )的優先順序高於 *,它就成了宣告一個函式p( 這個函式的返回值是指向整形變數的指標)。
賦值語句 p = max ; 作用是將函式 max 的入口地址賦給指標變數p。和陣列名代表陣列首元素地址類似,函式名代表該函式的入口地址。這時 p 就是指向函式 max 的指標變數,此時 p 和 max都指向函式開頭,呼叫 *p 就是呼叫 max 函式。
但是p作為指向函式的指標變數,它只能指向函式入口處而不可能指向函式中間的某一處指令處,因此不能用 *(p + 1)來表示指向下一條指令。
注意:(1) 指向函式的指標變數的一般定義形式為:
資料型別 (*指標變數名)(函式引數列表)
這裡資料型別就是函式返回值的型別
(2) int (* p) ( int,int ); 它只是定義一個指向函式的指標變數 p, 它不是固定指向哪一個函式的,而只是表示定義這樣一個型別的變數,它是專門用來存放函式的入口地址的。在程式中把哪一函式(該函式的值應該是整形的,且有兩個整形引數)的地址賦給它,他就指向哪一個函式。在一個函式中,一個函式指標變數可以先後指向同型別的不同函式。
(3) p = max; 在給函式指標變數賦值時,只需給出函式名而不必給出函式引數,因為是將函式的入口地址賦給 p ,而不涉及 實參和形參的結合問題,不能寫成 p = max(a,b);
(4) c = (*p)(a,b) 在函式呼叫時,只需將( *p ) 代替函式名即可,後面實參依舊。
(5) 對於指向函式的指標變數,像 p++ ,p+n.....是無意義的。
(二) 用指向函式的指標作為函式引數
函式指標變數通常的用途之一就是把指標作為引數傳遞到其他函式。
函式的引數可以是變數、指向變數的指標變數、陣列名、指向陣列的指標變數,也可以是指向函式的指標也可以作為引數,以實現函式地址的傳遞,這樣就能夠在被呼叫的函式中使用實參函式。
void sub ( int ( *x1) (int), int (*x2) (int,int) )
如果實參為兩個 函式名 f1 和 f2. 在函式首部定義x1、x2為函式指標變數,x1指向的函式有一個整形形參,x2指向的函式有兩個形參。i 和 j 是函式f1 和 f2所要的引數。
函式sub的形參 x1、x2(指標變數)在函式 sub 未被呼叫時並不佔用記憶體單元,也不指向任何函式。在sub被呼叫時,把實參函式 f1 和 f2的入口地址傳給形式指標變數 x1 和 x2.
既然在 sub 函式中要呼叫 f1 和 f2 函式,為什麼不直接呼叫f1 和 f2而要用函式指標變數呢? 確實,如果只是用到f1 和 f2 函式,完全可以在sub函式中直接呼叫f1 和 f2,而不必設指標變數 x1 和 x2。 但是,如果在每次呼叫sub時,呼叫的函式不是固定的,下次是f3 和 f4,再是f5 和 f6...
這時用指標變數就比較方便了。
3樓:過客守望者
指向函式
的指標的用法:
1.指向函式的指標的型別
指向函式的指標應該怎樣宣告?拿兩個字串的比較函式來說:
int str***pare(const string & s1, const string & s2) ;
如果兩個字串相等就返回0,否則,s1< s2返回負數,s1 > s2返回正數其實函式名不是其型別的一部分,函式型別是隻由它的返回型別和引數來決定。函式名稱只不過是指向函式**的地址。所以指向函式的指標的型別應該用下面的形式聲名:
int (*pf)( const string &, const string & );
2.初始化和賦值
完全匹配時初始化和賦值才是正確的如果不匹配則將產生編譯錯誤訊息在指向函式
型別的指標之間不存在隱式型別轉換。
int (*pfi)( const string &, const string & ) = str***pare;
指向函式的指標可以如下被賦值
pfi = str***pare;
pfi2 = pfi;
3.呼叫
如下**:
#include
using namespace std;
int min( int*, int );
int (*pf)( int*, int ) = min;
const int iasize = 5;
int ia[ iasize ] = ;
int main()
int min( int* ia, int sz )
4.函式指標的陣列
我們可以宣告一個函式指標的陣列例如
int (*testcases[10])();
將testcases 宣告為一個擁有10 個元素的陣列每個元素都是一個指向函式的函式指標,該函式沒有引數返回型別為int。
上面的宣告等價於下面宣告:
typedef int (*pfv)(); // 定義函式型別指標的typedef
pfv testcases[10];
函式指標的陣列可以用一個初始化列表來初始化該表中每個初始值都代表了一個與數
組元素型別相同的函式例如
int lexico***pare( const string &, const string & );
int size***pare( const string &, const string & );
typedef int ( *pfi2s )( const string &, const string & );
pfi2s ***parefuncs[2] =
;// 兩個等價的呼叫
pf***pare[ 0 ]( string1, string2 ); // 編寫
((*pf***pare)[ 0 ])( string1, string2 ); // 顯式
5,引數和返回型別
函式引數的型別不能是函式型別函式型別的引數將被自動轉換成該函式型別的指標
例如// typedef 表示一個函式型別
typedef int functype( const string &, const string & );
void sort( string *, string *, functype );
編譯器把sort()當作已經宣告為
void sort( string *, string *,
int (*)( const string &, const string & ) );
上面這兩個sort()的宣告是等價的
注意除了用作引數型別之外函式指標也可以被用作函式返回值的型別例如
int (*ff( int ))( int*, int );
該宣告將ff()宣告為一個函式它有一個int 型的引數返回一個指向函式的指標型別
為int (*) ( int*, int );
同樣使用typedef 名字可以使宣告更容易讀懂例如下面的typedef pf 使得我們能更
容易地分解出ff()的返回型別是函式指標
typedef int (*pf)( int*, int );
pf ff( int );
函式不能宣告返回一個函式型別如果是則產生編譯錯誤例如函式ff()不能如下
宣告// typedef 表示一個函式型別
typedef int func( int*, int );
func ff( int ); // 錯誤: ff()的返同型別為函式型別
4樓:劍俠→戰天意
看完以下的,您就知道什麼是指向函式的指標了,其實就是**函式!
程式設計師常常需要實現**。本文將討論函式指標的基本原則並說明如何使用函式指標實現**。注意這裡針對的是普通的函式,不包括完全依賴於不同語法和語義規則的類成員函式(類成員指標將在另文中討論)。
宣告函式指標
**函式是一個程式設計師不能顯式呼叫的函式;通過將**函式的地址傳給呼叫者從而實現呼叫。要實現**,必須首先定義函式指標。儘管定義的語法有點不可思議,但如果你熟悉函式宣告的一般方法,便會發現函式指標的宣告與函式宣告非常類似。
請看下面的例子:
void f();// 函式原型
上面的語句宣告瞭一個函式,沒有輸入引數並返回void。那麼函式指標的宣告方法如下:
void (*) ();
讓我們來分析一下,左邊圓括弧中的星號是函式指標宣告的關鍵。另外兩個元素是函式的返回型別(void)和由邊圓括弧中的入口引數(本例中引數是空)。注意本例中還沒有建立指標變數-只是宣告瞭變數型別。
目前可以用這個變數型別來建立型別定義名及用sizeof表示式獲得函式指標的大小:
// 獲得函式指標的大小
unsigned psize = sizeof (void (*) ());
// 為函式指標宣告型別定義
typedef void (*pfv) ();
pfv是一個函式指標的自定義型別,它指向的函式沒有輸入引數,返回類行為void。使用這個型別定義名可以隱藏複雜的函式指標語法。
指標變數應該有一個變數名:
void (*p) (); //p是指向某函式的指標
p是指向某函式的指標,該函式無輸入引數,返回值的型別為void。左邊圓括弧裡星號後的就是指標變數名。有了指標變數便可以賦值,值的內容是署名匹配的函式名和返回型別。例如:
void func()
p = func;
p的賦值可以不同,但一定要是函式的地址,並且署名和返回型別相同。
傳遞**函式的地址給呼叫者
現在可以將p傳遞給另一個函式(呼叫者)- caller(),它將呼叫p指向的函式,而此函式名是未知的:
void caller(void(*ptr)())
void func();
int main()
如果賦了不同的值給p(不同函式地址),那麼呼叫者將呼叫不同地址的函式。賦值可以發生在執行時,這樣使你能實現動態繫結。
呼叫規範
到目前為止,我們只討論了函式指標及**而沒有去注意ansi c/c++的編譯器規範。許多編譯器有幾種呼叫規範。如在visual c++中,可以在函式型別前加_cdecl,_stdcall或者_pascal來表示其呼叫規範(預設為_cdecl)。
c++ builder也支援_fastcall呼叫規範。呼叫規範影響編譯器產生的給定函式名,引數傳遞的順序(從右到左或從左到右),堆疊清理責任(呼叫者或者被呼叫者)以及引數傳遞機制(堆疊,cpu暫存器等)。
將呼叫規範看成是函式型別的一部分是很重要的;不能用不相容的呼叫規範將地址賦值給函式指標。例如:
// 被呼叫函式是以int為引數,以int為返回值
__stdcall int callee(int);
// 呼叫函式以函式指標為引數
void caller( __cdecl int(*ptr)(int));
// 在p中企圖儲存被呼叫函式地址的非法操作
__cdecl int(*p)(int) = callee; // 出錯
指標p和callee()的型別不相容,因為它們有不同的呼叫規範。因此不能將被呼叫者的地址賦值給指標p,儘管兩者有相同的返回值和引數列。
指標型別與指標所指向的型別指標型別與指標所指向的型別
不一定要相同。以前的機器有near和far指標,現在的機器一般都是32位指標。也就是說計算機用一個32位地址值定址。所以,所有指標其本身是佔用long位元組大小的。指標型別其實是告訴編譯器怎麼解釋指標所指向物件。當一個物件有資料成員,或者可以拆分成多部分資料物件時,可以做指標的型別轉換。不一定。例i...
C如何判斷指標是否指向有效的物件
可以在通過一個指標刪除任何一個物件後,都把這個指標置成null。另外,還沒有指向任何物件的指標也把它初始化成null。這樣,就可以 if p else 在宣告瞭指標變數以後,就可以利用該指標變數來對所指向的物件進行操縱,當然在進行操縱前必須保證所操縱的物件是有效的,即該指標不為空,否則會引起 記憶體...
指向多維陣列的指標變數問題
int p 4 這是一個指向一維陣列的指標,該語句表示定義一個指向由4個整型陣列元素組成的一維陣列的指標變數p,p儲存該一維陣列的起始地址。也就是說,樓主可以把int a 3 4 看成是一個包含4個元素的一維陣列,不過,樓主要注意的是,這個陣列中的元素也都是一個包含三個元素的整形一維陣列。p存放的就...