您好,登錄后才能下訂單哦!
一、函數(shù)指針
簡單聲明一個函數(shù)指針并不意味著它馬上就可以使用,和其它指針一樣,對函數(shù)指針執(zhí)行簡接訪問之前必須把它初始化為指向某一個函數(shù)。
int f(int);
int (*pf)(int)=&f;
第二個聲明創(chuàng)建了函數(shù)指針pf,并把它初始化為指向函數(shù)f。函數(shù)指針的初始化也可以通過一條賦值語句完成。在函數(shù)指針的初始化之前具有f的原型是很重要的,否則編譯器就無法檢查f的類型是否與pf所指向的類型一致。
初始化表達(dá)式中的&操作符是可選的,因為函數(shù)名被使用時總是由編譯器把它轉(zhuǎn)換為函數(shù)指針。&操作符只是顯示地說明了編譯器將隱式執(zhí)行的任務(wù)。
在函數(shù)指針被聲明并且初始化之后,我們就可以使用三種方式調(diào)用函數(shù):
int ret;
ret=f(30);
ret=(*pf)(30);
ret=pf(30);
第一條語句簡單的使用名字調(diào)用函數(shù)f,但它的執(zhí)行過程可能和我們想的不太一樣。函數(shù)名f首先被轉(zhuǎn)換為一個函數(shù)指針,該指針指定函數(shù)在內(nèi)存中的位置。然后,函數(shù)調(diào)用操作符調(diào)用該函數(shù),執(zhí)行開始于這個地址的代碼。
第二條語句對pf執(zhí)行簡接訪問操作,它把函數(shù)指針轉(zhuǎn)換為一個函數(shù)名。這個轉(zhuǎn)換并不是真正需要的,因為編譯器在執(zhí)行函數(shù)調(diào)用操作符之前又會把它轉(zhuǎn)換回去。不過,這條語句的效果和第一條語句是完全一樣的。
第三條語句和前兩條語句的效果是一樣的。簡接訪問并非必需,因為編譯器需要的是一個函數(shù)指針。這個例子顯示了函數(shù)指針通常是如何使用的。
那么什么時候我們應(yīng)該使用函數(shù)指針呢。兩個最常見的用途是把函數(shù)指針作為參數(shù)傳遞給函數(shù)以及用于轉(zhuǎn)換表。
二、回調(diào)函數(shù)
回調(diào)函數(shù),顧名思義,就是使用者自己定義一個函數(shù),使用者自己實現(xiàn)這個函數(shù)的程序內(nèi)容,然后把這個函數(shù)作為參數(shù)傳入別人(或系統(tǒng))的函數(shù)中,由別人(或系統(tǒng))的函數(shù)在運(yùn)行時來調(diào)用的函數(shù)。函數(shù)是你實現(xiàn)的,但由別人(或系統(tǒng))的函數(shù)在運(yùn)行時通過參數(shù)傳遞的方式調(diào)用,這就是所謂的回調(diào)函數(shù)。簡單來說,就是由別人的函數(shù)運(yùn)行期間來回調(diào)你實現(xiàn)的函數(shù)。
在系統(tǒng)編程的角度:當(dāng)程序跑起來時,一般情況下,應(yīng)用程序(application program)會時常通過API調(diào)用庫里所預(yù)先備好的函數(shù)。但是有些庫函數(shù)(library function)卻要求應(yīng)用先傳給它一個函數(shù),好在合適的時候調(diào)用,以完成目標(biāo)任務(wù)。這個被傳入的、后又被調(diào)用的函數(shù)就稱為回調(diào)函數(shù)(callback function)。
使用函數(shù)指針的一個例子就是回調(diào)函數(shù)。
例如如下函數(shù):
Node* search_ist(Node *node,void const *value,int (*compare)(void const *,void const *))
{
while(node(!=NULL){
if(compare(&node->value,value) ==0)
{
break;
}
node=node->link;
}
return node;
}
這是一個類型無關(guān)的鏈表查找,其中參數(shù)函數(shù)指針?biāo)赶虻暮瘮?shù)用于比較存儲于鏈表中類型的值。
在上邊的函數(shù)中我們把一個函數(shù)指針作為參數(shù)傳遞給其它函數(shù),后者將回調(diào)用戶的函數(shù)。任何時候,如果我們所編寫的函數(shù)必須能夠在不同的時刻執(zhí)行不同類型的工作或者執(zhí)行只能由函數(shù)調(diào)用者的工作,都可以使用這個技巧。許多窗口系統(tǒng)使用回調(diào)函數(shù)鏈接多個動作,如拖曳鼠標(biāo)和點(diǎn)擊按鈕來指定用戶程序中某個特定函數(shù)。
同樣也可以這樣使用,在一個特定的鏈表中進(jìn)行查找:
int compare_ints(void const *a,void const *b)
{
if(*(int)a == *(int *)b)
return 0;
else
return 1;
}
這個函數(shù)可以像下面這樣使用:
desired_node=search_list(root,&desired_value,compare_ints);
如果想在一個字符串鏈表中進(jìn)行查找,也可以這樣:
desired_node=search_list(root,"desired_value",strcmp);
不過有的編譯器可能會發(fā)出警告,因為strcmp的參數(shù)被聲明為char*而不是void*;
三、轉(zhuǎn)換表
如果有如下代碼:
switch(oper){
case ADD:
result=add(op1,op2);
break;
case SUB:
result=sub(op1,op2);
break;
case MUL:
result=mul(op1,op2);
break;
case DIV:
result=div(op1,op2);
break;
...
對于一個具有上百個操作符計算器而言,這條switch語句將會非常之長。
為了使用switch語句,表示操作符的代碼必須是整數(shù)。如果它們是從零開始的整數(shù),我們可以使用轉(zhuǎn)換表來完成相同的任務(wù)。轉(zhuǎn)換表就是一個函數(shù)指針數(shù)組。
創(chuàng)建一個轉(zhuǎn)換表需要兩個步驟。首先,聲明并初始化一個函數(shù)指針數(shù)組。函數(shù)的原型必須出現(xiàn)在這個數(shù)組的聲明之前。
double add{double,double};
double sub{double,double};
double mul{double,double};
double div{double,double};
...
double (*oper_func[])(double,double)={
add,sub,mul,div,...
};
初始化列表中各個函數(shù)的正確順序取決于程序中用于表示每個操作符的×××代碼。這個例子中假定ADD是0,SUB是1,MUL是2,DIV是3,以此類推。
第二個步驟是用下面這條語句替換前面整條switch語句。
result=oper_func[oper](op1,op2);
oper從數(shù)組中選擇正確的函數(shù)指針,而函數(shù)調(diào)用操作符將執(zhí)行這個函數(shù)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。