天天看點

函數指針和指針函數

在c語言中,一個函數總是占用一段連續的記憶體區,而函數名就是該函數所占記憶體區的首位址(入口位址),是以函數名跟數組名很類似,都是指針常量。

函數指針就是指向這個入口位址的指針變量,注意函數指針是一個變量。

void (*pf)(int)=&f;為什麼我們可以這樣定義函數指針呢?來自《c和指針》給出了這樣的解釋:函數名被使用時總是由編譯器把它轉換為函數指針,&操作符隻是顯示地說明了編譯器将隐式執行的任務 。

c語言協會定期集中讨論一次,每次讨論有一個主持者,每個主持者對應一個函數(函數功能可以是輸出主持者姓名及讨論主題或者完成其他功能)。現在要編寫這樣一段程式,輸入一個整數i(i>=0),根據輸入的i調用不同主持者的函數。很快就能寫出如下代碼:

這段代碼有錯誤嗎,肯定木有,運作結果完全正确。但是注意這裡隻列出了5種情況,如果總共有很多種情況呢,那麼我們就要寫一大堆的case語句。而且每次都是從case 1 開始判斷。那麼是否可以簡化代碼并且能讓程式不做這麼多判斷呢?這就引出了函數指針數組,顧名思義,就是存放函數指針的數組。現主函數修改如下所示:

void (*p[])()={Touch,DuanJiong,MeiKai,YinJun,JiangHaiLong};聲明了一個函數指針數組并指派。把每個函數的入口位址存入這個數組,這樣就不需要用switch語句了,根據下标i直接找到函數入口,省去了判斷的時間。

什麼是回調函數,來着百度百科的解釋:回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(位址)作為參數傳遞給另一個函數,當這個指針被用為調用它所指向的函數時,我們就說這是回調函數。這裡函數指針是作為參數傳遞給另一個函數。

大家都寫過冒泡排序吧,其代碼如下:

請注意到這樣一個不足,這個冒泡排序隻能對int型數組進行排序。如果我們想寫這樣一個函數,能同時對int型、float型、double型、char型、結構體類型...數組進行排序,該怎麼寫呢?也許你會想到函數重載,但是C語言沒有這個概念。這裡可以用函數指針來實作,其代碼比重載更簡潔,更高效這也是函數指針的最大用處,參考代碼:

請注意代碼中紅色部分代碼,要看懂這段代碼需明确兩個問題:(1)void*類型的指針未配置設定空間的,我們可以把它進行強制類型轉換成char*。(2)對數組元素進行交換時,并不是一次就把兩個數交換了,因為我們并不知道資料的确切類型。但知道數組元素的大小,這樣就可以逐個位元組進行交換。比如對int類型(占用四個位元組)的值a、b進行交換,先交換a、b的第一個位元組,然後第二個位元組...

了解了這個代碼,該怎麼用呢?參數要傳入一個函數指針,于是必須要寫一個比較兩個數大小的函數,且函數原型必須與int (*compare)(void *,void *)相比對。下面是測試各種類型數組排序的代碼:

運作結果:

函數指針和指針函數

再看看C語言标準庫中的快速排序函數,它的實作原理及用法同上述冒泡排序

函數指針和指針函數

繼續閱讀