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