函式指標是什麼?如何使用函式指標?函式指標到底有什麼大用?本文將一一介紹。
#include int test()
int main(void)
編譯:
gcc -o testfun testfun.c
$ nm testfun |grep test #檢視test函式的符號表資訊
0000000000400526 t test
宣告普通型別指標時,需要指明指標所指向的資料型別,而宣告函式指標時,也就要指明指標所指向的函式型別,即需要指明函式的返回型別和形參型別。例如對於下面的函式原型:
int sum(int,int);
它是乙個返回值為int型別,引數是兩個int型別的函式,那麼如何宣告該型別函式的指標呢?很簡單,將函式名替換成(*pf)形式即可,即我們把sum替換成(*fp)即可,fp為函式指標名,結果如下:
int (*fp)(int,int);
這樣就宣告了和sum函式型別相同的函式指標fp。這裡說明兩點,第一,*和fp為一體,說明了fp為指標型別,第二,*fp需要用括號括起來,否則就會變成下面的情況:
int *fp(int,int);
這種情況下,意思就大相徑庭了,它宣告了乙個引數為兩個int型別,返回值為int型別的指標的函式,而不再是乙個函式指標了。
在經常使用函式指標之後,我們很快就會發現,每次宣告函式指標都要帶上長長的形參和返回值,非常不便。這個時候,我們應該想到使用typedef,即為某型別的函式指標起乙個別名,使用起來就方便許多了。例如,對於前面提到的函式可以使用下面的方式宣告:
typedef int (*myfun)(int,int);//為該函式指標型別起乙個新的名字
myfun f1; //宣告myfun型別的函式指標f1
上面的myfun就是乙個函式指標型別,在其他地方就可以很方便地用來宣告變數了。typedef的使用不在本文的討論範圍,但是特別強調一句,typedef中宣告的型別在變數名的位置出現,理解了這一句,也就很容易使用typedef了。因而下面的方式是錯誤的:
typedef myfun (int)(int,int); //錯誤
typedef (int)(int,int) *myfun; //錯誤
賦值也很簡單,既然是指標,將對應指標型別賦給它既可。例如:
#includeint test(int a,int b)
typedef int(*fp)(int,int);
int main(void)
在這裡,宣告了返回型別為int,接受兩個int型別引數的函式指標f1和f2,分別給它們進行了賦值。表示式1和表示式2在作用上並沒有什麼區別。因為函式名在被使用時總是由編譯器把它轉換為函式指標,而前面加上&不過顯式的說明了這一點罷了。
呼叫也很容易,把它看成乙個普通的函式名即可:
#includeint test(int a,int b)
typedef int(*fp)(int,int);
int main(void)
在函式指標後面加括號,並傳入引數即可呼叫,其中表示式1和表示式2似乎都可以成功呼叫,但是哪個是正確的呢?ansi c認為這兩種形式等價。
函式指標的應用場景比較多,以庫函式qsort排序函式為例,它的原型如下:
void qsort(void *base,size_t nmemb,size_t size , int(*compar)(const void *,const void *));
看起來很複雜對不對?拆開來看如下:
void qsort(void *base, size_t nmemb, size_t size, );
拿掉第四個引數後,很容易理解,它是乙個無返回值的函式,接受4個引數,第乙個是void*型別,代表原始陣列,第二個是size_t型別,代表資料數量,第三個是size_t型別,代表單個資料占用空間大小,而第四個引數是函式指標。這第四個引數,即函式指標指向的是什麼型別呢?
int(*compar)(const void *,const void *)
很顯然,這是乙個接受兩個const void*型別入參,返回值為int的函式指標。
到這裡也就很清楚了。這個引數告訴qsort,應該使用哪個函式來比較元素,即只要我們告訴qsort比較大小的規則,它就可以幫我們對任意資料型別的陣列進行排序。
我們通過乙個例項來看函式指標怎麼使用。假設有一學生資訊,需要按照學生成績進行排序,該如何處理呢?
#include #include #define stu_name_len 16
/*學生資訊*/
typedef struct student_tag
student_t;
int studentcompare(const void *stu1,const void *stu2)
int main(void)
; student_t stu2 = ;
student_t stu3 = ;
student_t stu = ;
/*排序,將studentcompare作為引數傳入qsort*/
qsort((void*)stu,3,sizeof(student_t),studentcompare);
int loop = 0;
/**遍歷輸出*/
for(loop = 0; loop < 3;loop++)
return 0;
}
我們建立了乙個學生資訊結構,結構成員包括名字,學號和成績。main函式中建立了乙個包含三個學生資訊的陣列,並使用qsort函式對陣列按照學生成績進行排序。qsort函式第四個引數是函式指標,因此我們需要傳入乙個函式指標,並且這個函式指標的入參是cont void *型別,返回值為int。我們通過前面的學習知道了函式名本身就是指標,因此只需要將我們自己實現的studentcompare作為引數傳入即可。
最終執行結果如下:
name:two,id:2,score:77
name:three,id:3,score:88
name:one,id:1,score:99
可以看到,最終學生資訊按照分數從低到高輸出。
指標的指標有什麼用
指標的用處我知道 比如 int p 3 int x p x作為p的索引 那麼指標的指標呢,既然它出現在c中肯定有用,可是我實在不知道有什麼用,難道對指標進行索引,索引的索引?答 我給樓主乙個最直接的理由 那就是如果你希望在乙個函式的引數中改變乙個指標的值,你就只能傳這個指標的指標給這個函式。比如有i...
單鏈表為什麼用指向指標的指標
int a 1,b 2 void change int x void change int x void main 上面的例子很好的說明了傳遞指標與傳遞指標的指標的不同 所以在建立單鏈表時,由於需要修改傳遞給呼叫函式的頭指標的值,所以需要傳遞指向頭指標的指標 include include incl...
函式型別有什麼用?
函式型別通常用來宣告函式或者用來組成複雜的型別,例如 void foo c c 規定函式的返回值不能是函式型別或者陣列型別,只能用函式指標或者物件指標 來代替例如,有如下宣告 typedef int f void 這種型別的函式不帶引數,返回值是int。那麼可以這樣宣告f和g f f,g 相當於宣告...