C基礎(chǔ)篇之函數(shù)指針的介紹與運(yùn)用(內(nèi)含有簡易四則運(yùn)算計(jì)算器)

最近在探究Objective-C中block的實(shí)現(xiàn)原理,然后就不自覺的復(fù)習(xí)了一下C語言的函數(shù)指針算撮。正所謂萬變不離其宗,雖說OC中的block跟簡單的函數(shù)指針相比已經(jīng)大有不同,不過二者的表現(xiàn)形式還是有很多相似的地方杭攻。

首先做一個聲明:本文中的一些基礎(chǔ)理論知識,來自其他的技術(shù)博客或者論壇疤坝,為了尊重原創(chuàng)兆解,在這里將盡可能完整無損的呈現(xiàn)給想要夯實(shí)一下基礎(chǔ)知識的小伙伴。

在開始之前跑揉,可以先下載作者為這篇文章所寫的demo:簡易四則運(yùn)算器,總共代碼在100行左右痪宰,通過這個小demo來一窺函數(shù)指針的大概。

四則運(yùn)算計(jì)算器.gif

(附贈一款錄制gif的工具LICEcap畔裕,使用上跟蘋果的QuickTime相像衣撬,需要劃定一個錄制范圍,當(dāng)最后結(jié)束錄制的時候會自動為你生成gif圖扮饶。)

函數(shù)指針是什么具练?

先來看函數(shù)調(diào)用是怎么回事。一個函數(shù)占用一段連續(xù)內(nèi)存甜无。當(dāng)調(diào)用一個函數(shù)時扛点,實(shí)際上是跳轉(zhuǎn)到函數(shù)入口地址,執(zhí)行函數(shù)體的代碼岂丘,完成后返回陵究。如何找到對應(yīng)的入口地址?這是由函數(shù)名來標(biāo)記的奥帘,實(shí)際上铜邮,函數(shù)名就是函數(shù)的入口地址。

函數(shù)指針是一種特殊類型的指針寨蹋,它指向一個函數(shù)的入口地址松蒜。

注意:除了void類型指針是無類型的指針外,其他所有指針都是有對應(yīng)類型的已旧,例如int *pint秸苗、struct studentdata *psdata等,只有指明了指針?biāo)傅臄?shù)據(jù)類型运褪,編譯器才能為指針分配或預(yù)計(jì)分配相應(yīng)大小的存儲空間惊楼,指針的算術(shù)運(yùn)算如pint++等才是有意義的玖瘸。因此,定義了某種類型的指針之后檀咙,除非使用強(qiáng)制類型轉(zhuǎn)換店读,那么它只能指向相應(yīng)數(shù)據(jù)類型的變量或常量,不同類型的指針或數(shù)據(jù)之間不可混用攀芯。所以指針的類型實(shí)際上是一種身份標(biāo)志的作用屯断。

函數(shù)指針如何表明自己的身份呢?為了避免混亂侣诺,必須也要作出相應(yīng)規(guī)定殖演,不同函數(shù)的函數(shù)指針不能混用。例如年鸳,int func1(int arg11, char arg12)int func2(char arg)的函數(shù)指針就不能混用趴久,要定義可以指向func1的函數(shù)指針應(yīng)該這樣:

 int (*pfunc1)(int, char) = func1;

定義可以指向func2的函數(shù)指針則該如下:

int (*pfunc2)(char) = func2;

從函數(shù)指針的定義可以看出搔确,函數(shù)指針的類型實(shí)際上是由函數(shù)簽名決定的彼棍。函數(shù)簽名就象是函數(shù)的身份證,一個函數(shù)的函數(shù)簽名是獨(dú)一無二的膳算,具有相同函數(shù)簽名的函數(shù)實(shí)際上就是同一函數(shù)座硕。函數(shù)簽名包括函數(shù)名、函數(shù)形參類型的有序列表和函數(shù)返回值類型涕蜂。

一個函數(shù)指針的定義規(guī)定了它只能指向特定類型的函數(shù)华匾。如果兩個函數(shù)的形參列表和返回值類型相同,只有函數(shù)名和函數(shù)體不同机隙,則可以使用相同類型的函數(shù)指針蜘拉。

例如,如果還有一個函數(shù)int func3(char arg)有鹿,則上面定義的可以指向函數(shù)func2的函數(shù)指針也可以用于指向func3旭旭,即:
  pfunc2 = func3;
再使用pfunc2(char ARG)就可以調(diào)用函數(shù)func3,這時指令計(jì)數(shù)器(PC)指向函數(shù)入口葱跋,從此開始執(zhí)行函數(shù)體代碼持寄。

如何使用函數(shù)指針?

  • 定義合適類型的函數(shù)指針變量:int (*pfunc)(int, int);
  • 給函數(shù)指針變量賦值年局,使它指向某個函數(shù)入口:int example(int, int); pfunc = example;/將函數(shù)入口地址賦給函數(shù)指針變量/
  • 使用函數(shù)指針來調(diào)用相應(yīng)的函數(shù)际看;
    retval = pfunc(10, 16); 或者:retval = (*pfunc)(10, 16);

上面兩句都與retval = example(10, 16);等價。

理解:一個指針變量p實(shí)際上也和普通的變量一樣矢否,要占存儲空間(通常與平臺的虛擬地址一樣寬),也有其自身的存儲地址&p脑溢;不同的是僵朗,在指針變量p的值有特殊的意義赖欣,它是另外一個變量或常量的地址值,也就是說验庙,在地址為&p的存儲單元上存放著另外一個數(shù)據(jù)的地址顶吮。因此,p實(shí)際上是將p看作它指向的數(shù)據(jù)的地址來使用粪薛,操作符是引用相應(yīng)地址中的數(shù)據(jù)悴了,也就是對地址為p的存儲單元中存放的數(shù)據(jù)進(jìn)行操作。

為什么要使用函數(shù)指針违寿?

前面介紹了函數(shù)指針的基本知識和使用規(guī)范湃交。下面介紹函數(shù)指針的實(shí)際用途。不過首先要對前面的知識再做一個補(bǔ)充藤巢,因?yàn)橄旅娴膽?yīng)用很可能用到這一特性搞莺。前面指出,除函數(shù)名之外的函數(shù)簽名內(nèi)容(函數(shù)返回值類型和形參列表)決定了函數(shù)指針的類型掂咒。實(shí)際上還有一種特殊的或說通用的函數(shù)指針才沧,在定義這類函數(shù)指針時,只需要指定函數(shù)返回值類型绍刮,而留空形參列表温圆,這樣就可以指向返回值類型相同的所有函數(shù)。例如:
int (*pfunc)();
這樣定義的pfunc就可以指向前面提到的func1func2孩革,因?yàn)樗麄兌挤祷卣椭怠?br> 注意:int (*pfunc)()int (*pfunc)(void)不是一回事捌木,后者不允許接受任何參數(shù)。

函數(shù)指針最常見的三個用途是:

  • 作為參數(shù)傳遞給其他函數(shù)嫉戚。這樣可以把多個函數(shù)用一個函數(shù)體封裝起來刨裆,得到一個具有多個函數(shù)功能的新函數(shù),根據(jù)傳遞的函數(shù)指針變量值的不同彬檀,執(zhí)行不同的函數(shù)功能帆啃。這是函數(shù)嵌套調(diào)用難以實(shí)現(xiàn)的。參數(shù)的傳遞可以由程序員設(shè)定窍帝,也可以由用戶輸入讀取努潘,因此具有較大的靈活性和交互性。另外還可以用于回調(diào)函數(shù)坤学。使用void配合疯坤,還可以將對不同數(shù)據(jù)類型的數(shù)據(jù)進(jìn)行相同處理的多個函數(shù)封裝為一個函數(shù),增強(qiáng)函數(shù)的生命力深浮。

  • 用于散轉(zhuǎn)程序压怠。這種程序首先建立一個函數(shù)表(實(shí)際上是一個函數(shù)指針數(shù)組),表中存放了各個函數(shù)的入口地址(或函數(shù)名)飞苇,根據(jù)條件的設(shè)定來查表選擇執(zhí)行相應(yīng)的函數(shù)菌瘫。這樣也可以將多個函數(shù)封裝為一個函數(shù)或者程序蜗顽,散轉(zhuǎn)分支條件可以由程序員設(shè)定,也可以由用戶輸入讀取雨让,甚至是外設(shè)的某種特定狀態(tài)(這種狀態(tài)可以是不受人為控制的)雇盖。

  • 實(shí)現(xiàn)C的面向?qū)ο蟮念惖姆庋b。C語言中的struct與C++中的class有很大不同栖忠,除了缺省的成員屬性外(struct的成員缺省為public的崔挖,可隨意使用,而class成員缺省為private的)庵寞,struct還很難實(shí)現(xiàn)類成員函數(shù)的封裝狸相。struct的成員一般都是數(shù)據(jù)成員,而非函數(shù)成員皇帮。因此卷哩,為了在C語言中,為某個struct定義一套自己的函數(shù)對結(jié)構(gòu)數(shù)據(jù)成員進(jìn)行操作属拾,可以在struct結(jié)構(gòu)體中增加函數(shù)指針變量成員将谊,在初始化時使它指向特定函數(shù)即可。

基礎(chǔ)的理論知識就介紹這些渐白,下面來舉例分析四則運(yùn)算計(jì)算器demo中對函數(shù)指針的運(yùn)用尊浓。

首先是定義加減乘除的基本運(yùn)算如下。這是最基礎(chǔ)的運(yùn)算纯衍,不需要考慮調(diào)用的順序栋齿。

long long add(int a,int b){
    
    return a + b;
}

long long int sub(int a,int b){
    
    return a - b;
}

long long int mul(int a ,int b){
    
    return a*b;
    
}
long long int divi(int a,int b){
    
    return a/b;
}

然后觀察上面的函數(shù),發(fā)現(xiàn)除了函數(shù)名不一樣外襟诸,返回值與參數(shù)類型都是一樣的瓦堵,所以可以用一個函數(shù)指針來指向它們。

函數(shù)指針的聲明如下所示:

typedef long long int (*FUNC)();

FUNC pfunc;

首先定義了一個函數(shù)指針的類型:FUNC,這樣我們就可以更加方便的使用這個類型來聲明函數(shù)指針變量了歌亲。下面的FUNC pfunc;就是聲明了一個名為pfunc的函數(shù)指針變量菇用。

最后就是求和運(yùn)算了

double calculator(long long x,long long y,FUNC func){
    
    double result;

    result = (*func)(x,y);
    
    return result;
    
}

其中的func函數(shù)指針會根據(jù)我們所點(diǎn)擊的運(yùn)算符的不同而指向不同的函數(shù),這樣就實(shí)現(xiàn)了一個非常簡單的計(jì)算器了陷揪。

最后附上demo地址

參考資料:
http://www.360doc.com/content/13/1104/12/13670635_326518097.shtml

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惋鸥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子悍缠,更是在濱河造成了極大的恐慌卦绣,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件飞蚓,死亡現(xiàn)場離奇詭異滤港,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)玷坠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門蜗搔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來劲藐,“玉大人八堡,你說我怎么就攤上這事樟凄。” “怎么了兄渺?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵缝龄,是天一觀的道長。 經(jīng)常有香客問我挂谍,道長叔壤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任口叙,我火速辦了婚禮炼绘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妄田。我一直安慰自己俺亮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布疟呐。 她就那樣靜靜地躺著脚曾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪启具。 梳的紋絲不亂的頭發(fā)上本讥,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機(jī)與錄音鲁冯,去河邊找鬼拷沸。 笑死,一個胖子當(dāng)著我的面吹牛薯演,可吹牛的內(nèi)容都是我干的撞芍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼涣仿,長吁一口氣:“原來是場噩夢啊……” “哼勤庐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起好港,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤愉镰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后钧汹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丈探,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年拔莱,在試婚紗的時候發(fā)現(xiàn)自己被綠了碗降。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隘竭。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖讼渊,靈堂內(nèi)的尸體忽然破棺而出动看,到底是詐尸還是另有隱情,我是刑警寧澤爪幻,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布菱皆,位于F島的核電站,受9級特大地震影響挨稿,放射性物質(zhì)發(fā)生泄漏仇轻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一奶甘、第九天 我趴在偏房一處隱蔽的房頂上張望篷店。 院中可真熱鬧,春花似錦臭家、人聲如沸疲陕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸭轮。三九已至,卻和暖如春橄霉,著一層夾襖步出監(jiān)牢的瞬間窃爷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工姓蜂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留按厘,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓钱慢,卻偏偏與公主長得像逮京,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子束莫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容