chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

周立功手把手教你學(xué)嵌入式編程:函數(shù)指針與指針函數(shù)的應(yīng)用

AGk5_ZLG_zhiyua ? 來源:ZLG致遠電子 ? 作者:佚名 ? 2017-08-29 11:36 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

周立功教授數(shù)年之心血之作《程序設(shè)計與數(shù)據(jù)結(jié)構(gòu)》以及面向AMetal框架與接口編程(上)。書本內(nèi)容公開后,在電子行業(yè)掀起一片學(xué)習(xí)熱潮。經(jīng)周立功教授授權(quán),本公眾號特對《程序設(shè)計與數(shù)據(jù)結(jié)構(gòu)》一書內(nèi)容進行連載,愿共勉之。

第二章為程序設(shè)計技術(shù),本文為2.1.1 函數(shù)指針和2.1.2指針函數(shù)。

>>>>2.1函數(shù)指針與指針函數(shù)

>>>2.1.1函數(shù)指針

變量的指針指向的是一塊數(shù)據(jù),指針指向不同的變量,則取到的是不同的數(shù)據(jù)。而經(jīng)過編譯后的函數(shù)都是一段代碼,系統(tǒng)隨即為相應(yīng)的代碼分配一段存儲空間,而存儲這段代碼的起始地址(又稱為入口地址)就是這個函數(shù)的指針,即跳轉(zhuǎn)到某一個地址單元的代碼處去執(zhí)行。函數(shù)指針指向的是一段代碼(即函數(shù)),指針指向不同的函數(shù),則具有不同的行為。

因為函數(shù)名是一個常量地址,所以只要將函數(shù)的地址賦給函數(shù)指針即可調(diào)用相應(yīng)的函數(shù)。如同數(shù)組名一樣,我們用的是函數(shù)本身的名字,它會返回函數(shù)的地址。當一個函數(shù)名出現(xiàn)在表達式中時,編譯器就會將其轉(zhuǎn)換為一個指針,即類似于數(shù)組變量名的行為,隱式地取出了它的地址。即函數(shù)名直接對應(yīng)于函數(shù)生成的指令代碼在內(nèi)存中的地址,因此函數(shù)名可以直接賦值給指向函數(shù)的指針。既然函數(shù)指針的值可以改變,那么就可以使用同一個函數(shù)指針指向不同的函數(shù)。如果有以下定義:

int (*pf)(int); // pf函數(shù)指針的類型是什么?

C語言的發(fā)明者K&R是這樣解釋的,“因為*是前置運算符,它的優(yōu)先級低于(),為了讓連接正確地進行,有必要加上括號。”這未免有些牽強附會了,解釋來解釋去反而將人搞暈了。因為聲明中的*、()、[]都不是運算符,而運算符的優(yōu)先順序在語法規(guī)則中是在其它地方定義的。其詳解如下:

int(*pf)(int a); // pf是指向…的指針

int(*pf)(int a); // pf是指向…的函數(shù)(參數(shù)為int)的指針

int (*pf)(int a); // pf是指向返回int的函數(shù)(參數(shù)為int)的指針

即pf是一個指向返回int的函數(shù)的指針,它所指向的函數(shù)接受一個int類型的參數(shù)。 “int (*)(int)”類型名被解釋為指向返回int函數(shù)(參數(shù)為int)的指針類型。如果在該定義前添加typedef,比如:

typedef int (*pf)(int a);

未添加typedef前,pf是一個函數(shù)指針變量;而添加typedef后,pf就變成了函數(shù)指針類型,習(xí)慣的寫法是類型名pf大寫為PF。比如:

typedef int (*PF)(int a);

與其它類型的聲明不同,函數(shù)指針的聲明要求使用typedef關(guān)鍵字。另外,函數(shù)指針的聲明與函數(shù)原型的唯一不同是函數(shù)名用(*PF)代替了,“*”在此處表示“指向類型名為PF的函數(shù)”。顯然,有了PF類型即可定義函數(shù)指針變量pf1、pf2。比如:

PF pf1, pf2;

雖然此聲明等價于:

int (*pf1)(int a);

int (*pf2)(int a);

但這種寫法更難理解。既然函數(shù)指針變量是一個變量,那么它的值就是可以改變的,因此可以使用同一個函數(shù)指針變量指向不同的函數(shù)。使用函數(shù)指針必須完成以下工作:

●獲取函數(shù)的地址,比如,pf = add,pf = sub;

●聲明一個函數(shù)指針,比如,“int (*pf)(int, int);”;

●使用函數(shù)指針來調(diào)用函數(shù),比如,pf(5, 8),(*pf)(5, 8)。為何pf與(*pf)等價呢?

●一種說法是,由于pf是函數(shù)指針,假設(shè)pf指向add()函數(shù),則*pf就是函數(shù)add,因此使用(*pf)()調(diào)用函數(shù)。雖然這種格式不好看,但它給出了強有力的提示——代碼正在使用函數(shù)指針調(diào)用函數(shù)。

●另一種說法是,由于函數(shù)名是指向函數(shù)的指針,那么指向函數(shù)的指針的行為應(yīng)該與函數(shù)名相似,因此使用pf()調(diào)用函數(shù)。因為這種調(diào)用方式既簡單又優(yōu)雅,所以人們更愿意選擇——說明人類追隨美好感受的內(nèi)心是無法抗拒的。

雖然它們在邏輯上互相沖突,但不同的流派有不同的觀點,且容忍邏輯上無法自圓其說的觀點,正是人類思維活動的特點。

在一個袖珍計算器中,經(jīng)常需要用到加減乘除開方等各種各樣的計算,雖然其調(diào)用方法都是一樣,但在運行中需要根據(jù)具體情況決定選擇調(diào)用支持某一算法的函數(shù)。如果使用如圖 2.1(a)所示的直接調(diào)用方式,則勢必形成了依賴關(guān)系結(jié)構(gòu),策略會受到細節(jié)改變的影響,當使用如圖 2.1(b)所示的函數(shù)指針接口倒置(或反轉(zhuǎn))了這種依賴關(guān)系結(jié)構(gòu)時,則使得細節(jié)和策略都依賴于函數(shù)指針接口,斷開了不想要的直接依賴。

當將直接訪問抽象成函數(shù)指針倒置(或反轉(zhuǎn))了依賴的關(guān)系時,高層模塊不再依賴于低層模塊。高層模塊依賴于抽象,即一個函數(shù)指針形式的接口,同時細節(jié)也依賴于抽象,pf()實現(xiàn)了這個接口,即兩者都依賴于函數(shù)指針接口。在C語言中,通常用函數(shù)指針來實現(xiàn)DIP(倒置依賴關(guān)系),斷開不想要的直接依賴。既可以通過函數(shù)指針調(diào)用服務(wù)(被調(diào)用代碼),服務(wù)也可以通過函數(shù)指針回調(diào)用戶函數(shù)。都是一樣,但在運行中需要根據(jù)具體情況決定選擇調(diào)用支持某一算法的函數(shù)。如果使用如圖 2.1(a)所示的直接調(diào)用方式,則勢必形成了依賴關(guān)系結(jié)構(gòu),策略會受到細節(jié)改變的影響,當使用如圖 2.1(b)所示的函數(shù)指針接口倒置(或反轉(zhuǎn))了這種依賴關(guān)系結(jié)構(gòu)時,則使得細節(jié)和策略都依賴于函數(shù)指針接口,斷開了不想要的直接依賴。

圖 2.1 使用函數(shù)指針倒置依賴關(guān)系

函數(shù)指針是程序員經(jīng)常忽視的一個強大的語言能力,不僅使代碼更靈活可測,而且對消除重復(fù)條件邏輯有很大的幫助,同時還可以使調(diào)用者免于在編譯時或鏈接時依賴于某個特定的函數(shù),其極大地好處是減少了C語言模塊之間的耦合。但函數(shù)指針的使用是有條件的,如果主調(diào)函數(shù)與被調(diào)函數(shù)之間的調(diào)用關(guān)系永遠不會發(fā)生改變,則采用直接調(diào)用方式是最簡單的,在這種情況下,模塊之間耦合是合理的,不僅代碼簡單直截了當,而且開銷也是最小的。如果需要在運行時使用一個或多個函數(shù)指針調(diào)用某一函數(shù),則使用函數(shù)指針是最佳的選擇,通常將其稱之為動態(tài)接口,其范例程序詳見程序清單 2.1。

程序清單2.1通過函數(shù)指針調(diào)用函數(shù)范例程序(1)

1#include

2 int add(int a, int b)

3 {

4 printf("addition function ");

5 return a + b;

6 }

7

8 int sub(int a, int b)

9 {

10 printf("subtration function ");

11 return a - b;

12 }

13

14 int main(void)

15 {

16 int (*pf)(int, int);

17

18 pf = add;

19 printf("addition result:%d ", pf(5, 8));

20 pf = sub;

21 printf("subtration result:%d ", pf(8, 5));

22 return 0;

23 }

由于任何數(shù)據(jù)類型的指針都可以給void指針變量賦值,且函數(shù)指針的本質(zhì)就是一個地址,因此可以利用這一特性,將pf定義為一個void *類型指針,那么任何指針都可以賦值給void *類型指針變量。其調(diào)用方式如下:

void * pf = add;

printf("addition result:%d ", ((int (*)(int, int)) pf)(5, 8));

在函數(shù)指針的使用過程中,指針的值表示程序?qū)⒁D(zhuǎn)的地址,指針的類型表示程序的調(diào)用方式。在使用函數(shù)指針調(diào)用函數(shù)時,務(wù)必保證調(diào)用的函數(shù)類型與指向的函數(shù)類型完全相同,所以必須將void *類型轉(zhuǎn)換為((int (*)(int, int)) pf)來使用,其類型為“int (*)(int, int)”。

>>>2.1.2指針函數(shù)

實際上,指針變量的用途非常廣泛,指針不僅可以作為函數(shù)的參數(shù),而且指針還可以作為函數(shù)的返回值。當函數(shù)的返回值是指針時,則這個函數(shù)就是指針函數(shù)。當給定指向兩個整數(shù)的指針時,如程序清單 2.2所示的函數(shù)返回指向兩個整數(shù)中較大數(shù)的指針。當調(diào)用max時,用指向兩個int類型變量的指針作為參數(shù),且將結(jié)果存儲在一個指針變量中,其中,max函數(shù)返回的指針是作為實參傳入的兩個指針的一個。

程序清單2.2求最大值函數(shù)(指針作為函數(shù)的返回值)

1 #include

2 int *max(int *p1, int *p2)

3 {

4 if(*p1 > *p2)

5 return p1;

6 else

7 return p2;

8 }

9

10 int main(int argc, char *argv[])

11 {

12 int *p, a, b;

13 a = 1; b = 2;

14 p = max(&a, &b);

15 printf("%d ", *p);

16 return 0;

17 }

當然,函數(shù)也可以返回字符串,它返回的實際是字符串的地址,但一定要注意如何返回合法的地址。既可以返回是靜態(tài)的字符串地址,也可以在堆上分配字符串的內(nèi)存,然后返回其地址。注意,不要返回局部字符串的地址,因為內(nèi)存有可能被別的棧幀覆寫。

下面我們再來看一看,指針函數(shù)與函數(shù)指針變量有什么區(qū)別?如果有以下定義:

int *pf(int *, int); // int *(int *, int)類型

int (*pf)(int, int); // int (*)(int, int)類型

雖然兩者之間只差一個括號,但表示的意義卻截然不同。函數(shù)指針變量的本質(zhì)是一個指針變量,其指向的是一個函數(shù);指針函數(shù)的本質(zhì)是一個函數(shù),即將pf聲明為一個函數(shù),它接受2個參數(shù),其中一個是int *,另一個是int,其返回值是一個int類型的指針。

在指針函數(shù)中,還有一類這樣的函數(shù),其返回值是指向函數(shù)的指針。對于初學(xué)者,別說寫出這樣的函數(shù)聲明,就是看到這樣的寫法也是一頭霧水。比如,下面這樣的語句:

int (*ff (int))(int, int); // ff是一個函數(shù)

int (* ff (int))(int, int); // ff是一個指針函數(shù),其返回值是指針

int(* ff (int))(int, int); //指針指向的是一個函數(shù)

這種寫法確實讓人非常難懂,以至于一些初學(xué)者產(chǎn)生誤解,認為寫出別人看不懂的代碼才能顯示自己水平高。而事實上恰好相反,能否寫出通俗易懂的代碼是衡量程序員是否優(yōu)秀的標準。當使用typedef后,則PF就成為了一個函數(shù)指針類型。即:

typedef int (*PF)(int, int);

有了這個類型,那么上述函數(shù)的聲明就變得簡單多了。即:

PF ff(int);

下面將以程序清單 2.3為例,說明用函數(shù)指針作為函數(shù)返回值的用法。當用戶分別輸入d、x和p時,求數(shù)組的最大值、最小值和平均值。

程序清單2.3求最值與平均值范例程序

1 #include

2 #include

3 double getMin(double *dbData, int iSize) //求最小值

4 {

5 double dbMin;

6

7 assert((dbData != NULL) && (iSize > 0));

8 dbMin = dbData[0];

9 for (int i = 1; i < iSize; i++){?

10 if (dbMin > dbData[i]){

11 dbMin = dbData[i];

12 }

13 }

14 return dbMin;

15 }

16

17 double getMax(double *dbData, int iSize) //求最大值

18 {

19 double dbMax;

20

21 assert((dbData != NULL) && (iSize > 0));

22 dbMax = dbData[0];

23 for (int i = 1; i < iSize; i++){

24 if (dbMax < dbData[i]){?

25 dbMax = dbData[i];

26 }

27 }

28 return dbMax;

29 }

30

31 double getAverage(double *dbData, int iSize) //求平均值

32 {

33 double dbSum = 0;

34

35 assert((dbData != NULL) && (iSize > 0));

36 for (int i = 0; i < iSize; i++){

37 dbSum += dbData[i];

38 }

39 return dbSum/iSize;

40 }

41

42 double unKnown(double *dbData, int iSize) //未知算法

43 {

44 return 0;

45 }

46

47 typede double (*PF)(double *dbData, int iSize); //定義函數(shù)指針類型

48 PF getOperation(char c) //根據(jù)字符得到操作類型,返回函數(shù)指針

49 {

50 switch (c){

51 case 'd':

52 return getMax;

53 case 'x':

54 return getMin;

55 case 'p':

56 return getAverage;

57 default:

58 return unKnown;

59 }

60 }

61

62 int main(void)

63 {

64 double dbData[] = {3.1415926, 1.4142, -0.5, 999, -313, 365};

65 int iSize = sizeof(dbData) / sizeof(dbData[0]);

66 char c;

67

68 printf("Please input the Operation : ");

69 c = getchar();

70 PF pf = getOperation(c);

71 printf("result is %lf ", pf(dbData, iSize));

72 return 0;

73 }

前4個函數(shù)分別實現(xiàn)了求最大值、最小值、平均值和未知算法,getOperation()根據(jù)輸入字符得到的返回值是以函數(shù)指針的形式返回的,從pf(dbData, iSize)可以看出是通過這個指針調(diào)用函數(shù)的。注意,指針函數(shù)可以返回新的內(nèi)存地址、全局變量的地址和靜態(tài)變量的地址,但不能返回局部變量的地址,因為函數(shù)結(jié)束后,在函數(shù)內(nèi)部的聲明的局部變量的聲明周期已經(jīng)結(jié)束,內(nèi)存將自動放棄。顯然,在主調(diào)函數(shù)中訪問這個指針所指向的數(shù)據(jù),將會產(chǎn)生不可預(yù)料的結(jié)果。

想學(xué)更多嵌入式課程,請掃描下圖二維碼,馬上學(xué)習(xí)!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 指針
    +關(guān)注

    關(guān)注

    1

    文章

    484

    瀏覽量

    71195
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    40749
  • 程序設(shè)計
    +關(guān)注

    關(guān)注

    3

    文章

    262

    瀏覽量

    31021
  • 函數(shù)指針
    +關(guān)注

    關(guān)注

    2

    文章

    57

    瀏覽量

    3976
  • 指針函數(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    2889
  • ametal
    +關(guān)注

    關(guān)注

    2

    文章

    24

    瀏覽量

    11566

原文標題:周立功:函數(shù)指針與指針函數(shù)的應(yīng)用

文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    手把手教你學(xué)VC

    手把手教你學(xué)VC
    發(fā)表于 08-20 15:02

    手把手教你學(xué)CPLD/FPGA與單片機聯(lián)合設(shè)計》-興華

    。此外,為了幫助讀者掌握單片機與CPLD/FPGA的聯(lián)合設(shè)計,還介紹了51單片機的基本知識及單片機c語言編程的基礎(chǔ)知識,并通過實例設(shè)計進行詳解?!?b class='flag-5'>手把手教你學(xué)CPLD/FPGA與單片機
    發(fā)表于 12-29 17:10

    手把手教你學(xué)CPLD/FPGA與單片機聯(lián)合設(shè)計》-興華

    。此外,為了幫助讀者掌握單片機與CPLD/FPGA的聯(lián)合設(shè)計,還介紹了51單片機的基本知識及單片機c語言編程的基礎(chǔ)知識,并通過實例設(shè)計進行詳解。《手把手教你學(xué)CPLD/FPGA與單片機
    發(fā)表于 01-06 17:21

    手把手教你學(xué)FPGA 編程規(guī)范篇

    手把手教你學(xué)FPGA 編程規(guī)范篇
    發(fā)表于 02-02 11:32

    手把手教你學(xué)STM32單片機

    整理資料來源【正點原子】 手把手教你學(xué)STM32單片機教學(xué)視頻 嵌入式 之 F103-基于新戰(zhàn)艦V]NANO_STM32F103開發(fā)指南-HAL庫版本_V1.0.pdf其它網(wǎng)絡(luò)操作等詞
    發(fā)表于 08-19 07:08

    手把手教你學(xué)DSP28335_張卿杰

    手把手教你學(xué)DSP28335張卿杰百度云分享手把手教你學(xué)DSP28335張卿杰百度云分享
    發(fā)表于 01-11 11:45 ?178次下載

    指針作為函數(shù)參數(shù)

    手把手教你C語言難點編程,很好的C語言編程基礎(chǔ)資料,歡迎下載學(xué)習(xí)。
    發(fā)表于 03-25 15:28 ?2次下載

    手把手教你學(xué)電子書制作

    手把手教你學(xué)電子書制作,可以自己DIY電子書
    發(fā)表于 09-13 11:26 ?0次下載

    c語言函數(shù)指針定義,指針函數(shù)函數(shù)指針的區(qū)別

     往往,我們一提到指針函數(shù)函數(shù)指針的時候,就有很多人弄不懂。下面就由小編詳細為大家介紹C語言中函數(shù)指針
    發(fā)表于 11-16 15:18 ?3870次閱讀

    手把手教你如何開始DSP編程

    手把手教你如何開始DSP編程。
    發(fā)表于 04-09 11:54 ?13次下載
    <b class='flag-5'>手把手</b><b class='flag-5'>教你</b>如何開始DSP<b class='flag-5'>編程</b>

    手把手教你學(xué)LabVIEW視覺設(shè)計

    手把手教你學(xué)LabVIEW視覺設(shè)計手把手教你學(xué)LabVIEW視覺設(shè)計
    發(fā)表于 03-06 01:41 ?3327次閱讀

    理解函數(shù)指針函數(shù)指針數(shù)組、函數(shù)指針數(shù)組的指針

    理解函數(shù)指針函數(shù)指針數(shù)組、函數(shù)指針數(shù)組的指針
    的頭像 發(fā)表于 06-29 15:38 ?1.5w次閱讀
    理解<b class='flag-5'>函數(shù)</b><b class='flag-5'>指針</b>、<b class='flag-5'>函數(shù)</b><b class='flag-5'>指針</b>數(shù)組、<b class='flag-5'>函數(shù)</b><b class='flag-5'>指針</b>數(shù)組的<b class='flag-5'>指針</b>

    嵌入式秘術(shù)】手把手教你如何劫持RTOS(下)

    在《【嵌入式秘術(shù)】手把手教你如何劫持RTOS(上)》中,我們做了簡單的熱身——介紹了一種在你擁有某一個庫的源代碼或者.lib文件時,如何...
    發(fā)表于 01-25 18:51 ?7次下載
    【<b class='flag-5'>嵌入式</b>秘術(shù)】<b class='flag-5'>手把手</b><b class='flag-5'>教你</b>如何劫持RTOS(下)

    手把手教你學(xué)FPGA仿真

    電子發(fā)燒友網(wǎng)站提供《手把手教你學(xué)FPGA仿真.pdf》資料免費下載
    發(fā)表于 10-19 09:17 ?2次下載
    <b class='flag-5'>手把手</b><b class='flag-5'>教你</b><b class='flag-5'>學(xué)</b>FPGA仿真

    面試???1:函數(shù)指針指針函數(shù)、數(shù)組指針指針數(shù)組

    嵌入式開發(fā)領(lǐng)域,函數(shù)指針指針函數(shù)、數(shù)組指針指針
    的頭像 發(fā)表于 08-10 08:11 ?1456次閱讀
    面試常考+1:<b class='flag-5'>函數(shù)</b><b class='flag-5'>指針</b>與<b class='flag-5'>指針</b><b class='flag-5'>函數(shù)</b>、數(shù)組<b class='flag-5'>指針</b>與<b class='flag-5'>指針</b>數(shù)組