十年網站開發(fā)經驗 + 多家企業(yè)客戶 + 靠譜的建站團隊
量身定制 + 運營維護+專業(yè)推廣+無憂售后,網站問題一站解決
學習了數組之后,我們知道數組是在內存中申請一塊內存空間;數組名代表內存塊的首地址,通過數組名可以訪問內存塊中的數據。
我們提供的服務有:成都網站制作、成都做網站、微信公眾號開發(fā)、網站優(yōu)化、網站認證、江陵ssl等。為成百上千家企事業(yè)單位解決了網站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的江陵網站制作公司
那么,對于函數,它也是存放在內存塊中的一段數據。例如下面的函數:
void func( int a )
{
printf( "in func, a = %d " , a );
}
此時,定義了一個函數名是func的函數??梢匀缦抡{用該函數:
func(100);
此時,就進入了func函數的函數體中執(zhí)行??梢钥吹剑?函數名如同數組名一樣,代表函數所在內存塊的首地址 。通過數組名可以訪問數組在內存塊中申請的內存,同理,通過函數名,可以訪問函數在內存中存放的數據。
所以,函數名就代表了該函數在內存塊中存放的首地址。那么,函數名是表示一個地址,就可以把這個地址值存放在某一個指針變量中,然后,通過指針變量訪問函數名指向的函數。
在C語言中,提供了函數指針變量,可以存放函數名表示的地址。函數指針變量的定義格式如下:
返回數據類型 (*函數指針變量名)(形參列表)
對比函數的定義如下:
返回數據類型 函數名(形參列表)
可以看到,函數指針變量的定義,與函數的定義格式基本一樣,唯一的區(qū)別是把“函數名”轉換為“*(函數指針變量名)”;總結如下:
(1) 使用指針降級運算符*來定義,表示這個是一個指針。
(2) 指針降級運算符*不可以靠近返回數據類型,例如“返回數據類*”就表示函數的返回類型是一個指針。那么,為了讓指針降級運算符*能夠修飾函數指針變量,就用小括號()把指針降級運算符*與函數指針變量名包含起來。
定義了函數指針變量之后,可以把函數名賦給函數指針變量。因為,函數名就表示函數在內存塊中的首地址,所以,可以直接把一個地址賦值給函數指針變量。格式如下:
函數指針變量 = 函數名;
最終,可以通過函數指針變量調用函數,調用的格式與通過函數名調用完全一樣,通過函數指針變量調用函數,有如下形式:
方法1:函數指針變量(實參列表);
方法2:(*函數指針變量名)(實參列表);
很多情況下,我們更傾向于使用第一種形式,因為,它的使用方式更接近于通過函數名調用函數。
下面根據程序測試例子來看看怎么樣應用函數指針變量。
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
程序運行結果如下:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
可以看到,我們定義了func函數和函數指針變量pfunc,然后,把函數名func設置給函數指針變量pfunc,最終,通過函數指針變量pfunc調用函數。
因為函數指針變量存放的就是函數名表示的地址,所以,函數指針變量與函數名一樣,可以直接通過函數指針變量調用函數。
注意:我們在學習指針的時候,可以把一個int類型的變量地址賦值給int類型的指針;但是,不可以把int類型變量的地址,賦值給double類型的指針。這就是變量數據類型不一致的問題。
同樣的道理,定義函數的時候,函數的返回數據類型和形參列表都不一樣,所以,函數指針變量能夠接收的函數名,它們定義的 函數返回數據類型和形參列表必須一致 ,此時,就如同變量與指針變量類型一致時,才可以把變量的地址賦值給指針變量一樣。
如下是一個測試例子:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
程序編譯結果如下:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
可以看到,我們把func函數的形參列表修改為double,但是,函數指針變量pfunc定義的形參列表為int類型,此時,函數和函數指針變量的定義格式不一致,所以,不可以把函數名表示的地址設置給函數指針變量。我們來總結一下:
(1) 在Ubuntu系統(tǒng)中,使用GCC編譯,提示warning警告,但是,程序可以編譯通過,可以運行。
(2) 在Windows系統(tǒng)中,使用Visual Studio工具,無法編譯該代碼,提示類型不一致。
(3) 從代碼的嚴謹方面來說,是不可以設置類型不一致的數據。所以,我們應該編寫嚴謹的代碼,函數定義的類型,與函數指針類型不一致的時候,不可以把函數名,賦值給函數指針變量。
函數指針變量的定義很重要,我們需要牢記和理解它們使用的方式。下面多舉幾個例子說明函數指針變量的定義和使用。
int func( void );
int (*pfunc)( void );
pfunc = func;
此時,定義func函數,它的返回值類型是int類型,形參列表是void,那么,定義pfunc函數指針變量的時候,它的返回值類型與形參列表都必須與func一樣。
char * func1( int x, int y, int x);
char * (*pfunc1)( int , int , int );
pfunc1 = func1;
char * (*pfunc1)( int x, int y, int x);
我們再總結一下:
(1) 函數名表示函數在內存塊中的首地址,可以直接把函數名賦值給函數指針變量;
(2) 定義函數指針變量的時候,函數返回數據類型和形參列表必須與要指向函數的定義一致;
void*?f(int);?//一個指針函數f
void*(*p)(int)?=?f;?//一個指向f的函數指針p
1
typedef int (*Fptr)(int , int );
Fptr fptr = NULL; (此處的Fptr是數據類型?)
使用了typedef,F(xiàn)ptr就是數據類型,代表int (*XXX)(int , int );這一堆
如果寫成Fptr fptr,意思就是int (*fptr)(int , int );了
你的理解沒有錯,F(xiàn)ptr就是返回值是int,參數是兩個int的函數指針類型,fptr才是函數指針變量
2
int (*Fptr)(int , int ) ;
Fptr = NULL; (此處的Fptr是函數指針變量?)
Fptr就是一個返回值是int,參數是兩個int的函數指針變量了
針對你的: void kk(void) { cout "kk " endl; } 或其相同原型的函數作如下聲明: typedef void(*FuncKk)(void);//FuncKk是這一原型函數的指針類型; 這樣你可以在你的程序中如下: int main() { FuncKk _pfunc = kk;//定義一個FuncKk型的函數指針并初始化; _pfunc();//用該函數指針調用kk函數 _PAUSE; return 0; } 上述程序行為良好,體現(xiàn)出標準的函數指針使用方法,即使用typedef聲明函數指針的類型而不是函數指針變量,好處是一處聲明,到處都可以使用而避免多次使用函數指針冗長的語法,還有typedef固有的靈活性。