在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 設計應用 > 編程小技巧:如何提升編程能力?

            編程小技巧:如何提升編程能力?

            作者: 時間:2025-01-23 來源: 收藏

            指針

            本文引用地址:http://www.biyoush.com/article/202501/466584.htm

            在講回調之前,我們需要了解指針。C語言的靈魂是指針,我們經(jīng)常使用整型指針,字符串指針,結構體指針等。

            int *p1;
            char *p2;
            STRUCT *p3; //STRUCT為我們定義的結構體

            但是好像我們一般很少使用函數(shù)指針,我們一般使用函數(shù)都是直接使用函數(shù)調用。下面我們來了解一下函數(shù)指針的概念和使用方法。

            1. 概念

            函數(shù)指針是指向函數(shù)的指針變量。通常我們說的指針變量是指向一個整型、字符型或數(shù)組等變量,而函數(shù)指針是指向函數(shù)。

            函數(shù)指針可以像一般函數(shù)一樣,用于調用函數(shù)、傳遞參數(shù)。

            函數(shù)指針的定義方式為:

            函數(shù)返回值類型 (* 指針變量名) (函數(shù)參數(shù)列表);

            “函數(shù)返回值類型”表示該指針變量可以指向具有什么返回值類型的函數(shù);“函數(shù)參數(shù)列表”表示該指針變量可以指向具有什么參數(shù)列表的函數(shù)。這個參數(shù)列表中只需要寫函數(shù)的參數(shù)類型即可。

            我們看到,函數(shù)指針的定義就是將“函數(shù)聲明”中的“函數(shù)名”改成“(指針變量名)”。但是這里需要注意的是:“(指針變量名)”兩端的括號不能省略,括號改變了運算符的優(yōu)先級。如果省略了括號,就不是定義函數(shù)指針而是一個函數(shù)聲明了,即聲明了一個返回值類型為指針型的函數(shù)。

            那么怎么判斷一個指針變量是指向變量的指針變量還是指向函數(shù)的指針變量呢?首先看變量名前面有沒有“”,如果有“”說明是指針變量;其次看變量名的后面有沒有帶有形參類型的圓括號,如果有就是指向函數(shù)的指針變量,即函數(shù)指針,如果沒有就是指向變量的指針變量。

            最后需要注意的是,指向函數(shù)的指針變量沒有 ++ 和 – 運算。

            一般為了方便使用,我們會選擇:

            typedef 函數(shù)返回值類型 (* 指針變量名) (函數(shù)參數(shù)列表);

            比如:

            typedef int (*Fun1)(int);//聲明也可寫成int (*Fun1)(int x),但習慣上一般不這樣。
            typedef int (*Fun2)(intint);//參數(shù)為兩個整型,返回值為整型
            typedef void (*Fun3)(void);//無參數(shù)和返回值
            typedef void* (*Fun4)(void*);//參數(shù)和返回值都為void*指針

            2. 如何用函數(shù)指針調用函數(shù)

            給大家舉一個例子:

            int Func(int x);   /*聲明一個函數(shù)*/
            int (*p) (int x);  /*定義一個函數(shù)指針*/
            p = Func;          /*將Func函數(shù)的首地址賦給指針變量p*/
            p = &Func;          /*將Func函數(shù)的首地址賦給指針變量p*/

            賦值時函數(shù) Func 不帶括號,也不帶參數(shù)。由于函數(shù)名 Func 代表函數(shù)的首地址,因此經(jīng)過賦值以后,指針變量 p 就指向函數(shù) Func() 代碼的首地址了。

            下面來寫一個程序,看了這個程序你們就明白函數(shù)指針怎么使用了:

            #include <stdio.h>
            int Max(intint);  //函數(shù)聲明
            int main(void){
                int(*p)(intint);  //定義一個函數(shù)指針
                int a, b, c;
                p = Max;  //把函數(shù)Max賦給指針變量p, 使p指向Max函數(shù)
                printf("please enter a and b:");
                scanf("%d%d", &a, &b);
                c = (*p)(a, b);  //通過函數(shù)指針調用Max函數(shù)
                printf("a = %dnb = %dnmax = %dn", a, b, c);
                return 0;
            }
            int Max(int x, int y)  //定義Max函數(shù){
                int z;
                if (x > y)
                {
                    z = x;
                }
                else
                {
                    z = y;
                }
                return z;
            }

            特別注意的是,因為函數(shù)名本身就可以表示該函數(shù)地址(指針),因此在獲取函數(shù)指針時,可以直接用函數(shù)名,也可以取函數(shù)的地址。

            p = Max可以改成 p = &Max
            c = (*p)(a, b) 可以改成 c = p(a, b)

            3. 函數(shù)指針作為某個函數(shù)的參數(shù)

            既然函數(shù)指針變量是一個變量,當然也可以作為某個函數(shù)的參數(shù)來使用的。

            示例:

            #include <stdio.h>
            #include <stdlib.h>
            typedef void(*FunType)(int);
            //前加一個typedef關鍵字,這樣就定義一個名為FunType函數(shù)指針類型,而不是一個FunType變量。
            //形式同 typedef int* PINT;
            void myFun(int x);
            void hisFun(int x);
            void herFun(int x);
            void callFun(FunType fp,int x);
            int main(){
                callFun(myFun,100);//傳入函數(shù)指針常量,作為回調函數(shù)
                callFun(hisFun,200);
                callFun(herFun,300);
                return 0;
            }
            void callFun(FunType fp,int x){
                fp(x);//通過fp的指針執(zhí)行傳遞進來的函數(shù),注意fp所指的函數(shù)有一個參數(shù)
            }
            void myFun(int x){
                printf("myFun: %dn",x);
            }
            void hisFun(int x){
                printf("hisFun: %dn",x);
            }
            void herFun(int x){
                printf("herFun: %dn",x);
            }

            輸出:

            640-3.jpeg

            4. 函數(shù)指針作為函數(shù)返回類型

            有了上面的基礎,要寫出返回類型為函數(shù)指針的函數(shù)應該不難了,下面這個例子就是返回類型為函數(shù)指針的函數(shù):

            void (* func5(intintfloat ))(intint)
            {
                ...
            }

            在這里, func5 以 (int, int, float) 為參數(shù),其返回類型為 void (*)(int, int) 。在C語言中,變量或者函數(shù)的聲明也是一個大學問。

            5. 函數(shù)指針數(shù)組

            在開始講解回調函數(shù)前,最后介紹一下函數(shù)指針數(shù)組。既然函數(shù)指針也是指針,那我們就可以用數(shù)組來存放函數(shù)指針。下面我們看一個函數(shù)指針數(shù)組的例子:

            /* 方法1 */
            void (*func_array_1[5])(intintfloat);
            /* 方法2 */
            typedef void (*p_func_array)(intintfloat);
            p_func_array func_array_2[5];

            上面兩種方法都可以用來定義函數(shù)指針數(shù)組,它們定義了一個元素個數(shù)為5,類型是 *void (*)(int, int, float)*的函數(shù)指針數(shù)組。

            6. 函數(shù)指針總結

            · 函數(shù)指針常量 :Max;函數(shù)指針變量:p;

            · 數(shù)名調用如果都得如(*myFun)(10)這樣,那書寫與讀起來都是不方便和不習慣的。所以C語言的設計者們才會設計成又可允許myFun(10)這種形式地調用(這樣方便多了,并與數(shù)學中的函數(shù)形式一樣)。

            · 函數(shù)指針變量也可以存入一個數(shù)組內。數(shù)組的聲明方法:int (*fArray[10]) ( int );

            回調函數(shù)

            1. 什么是回調函數(shù)

            我們先來看看百度百科是如何定義回調函數(shù)的:

            回調函數(shù)就是一個通過函數(shù)指針調用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當這個指針被用來調用其所指向的函數(shù)時,我們就說這是回調函數(shù)?;卣{函數(shù)不是由該函數(shù)的實現(xiàn)方直接調用,而是在特定的事件或條件發(fā)生時由另外的一方調用的,用于對該事件或條件進行響應。

            通過一幅圖來說明什么是回調:

            640-11.png

            假設我們要使用一個排序函數(shù)來對數(shù)組進行排序,那么在主程序(Main program)中,我們先通過庫,選擇一個庫排序函數(shù)(Library function)。但排序算法有很多,有冒泡排序,選擇排序,快速排序,歸并排序。同時,我們也可能需要對特殊的對象進行排序,比如特定的結構體等。庫函數(shù)會根據(jù)我們的需要選擇一種排序算法,然后調用實現(xiàn)該算法的函數(shù)來完成排序工作。這個被調用的排序函數(shù)就是回調函數(shù)(Callback function)。

            結合這幅圖和上面對回調函數(shù)的解釋,我們可以發(fā)現(xiàn),要實現(xiàn)回調函數(shù),最關鍵的一點就是要將函數(shù)的指針傳遞給一個函數(shù)(上圖中是庫函數(shù)),然后這個函數(shù)就可以通過這個指針來調用回調函數(shù)了。注意,回調函數(shù)并不是C語言特有的,幾乎任何語言都有回調函數(shù)。在C語言中,我們通過使用函數(shù)指針來實現(xiàn)回調函數(shù)。

            把一段可執(zhí)行的代碼像參數(shù)傳遞那樣傳給其他代碼,而這段代碼會在某個時刻被調用執(zhí)行,這就叫做回調

            如果代碼立即被執(zhí)行就稱為同步回調,如果過后再執(zhí)行,則稱之為異步回調。

            回調函數(shù)就是一個通過函數(shù)指針調用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當這個指針被用來調用其所指向的函數(shù)時,我們就說這是回調函數(shù)。

            回調函數(shù)不是由該函數(shù)的實現(xiàn)方直接調用,而是在特定的事件或條件發(fā)生時由另外的一方調用的,用于對該事件或條件進行響應。

            2. 為什么要用回調函數(shù)

            因為可以把調用者與被調用者分開,所以調用者不關心誰是被調用者。它只需知道存在一個具有特定原型和限制條件的被調用函數(shù)。

            簡而言之,回調函數(shù)就是允許用戶把需要調用的方法的指針作為參數(shù)傳遞給一個函數(shù),以便該函數(shù)在處理相似事件的時候可以靈活的使用不同的方法。

            int Callback()    ///< 回調函數(shù){
                // TODO
                return 0;
            }
            int main()     ///<  主函數(shù){
                // TODO
                Library(Callback);  ///< 庫函數(shù)通過函數(shù)指針進行回調
                // TODO
                return 0;
            }

            回調似乎只是函數(shù)間的調用,和普通函數(shù)調用沒啥區(qū)別。但仔細看,可以發(fā)現(xiàn)兩者之間的一個關鍵的不同:在回調中,主程序把回調函數(shù)像參數(shù)一樣傳入庫函數(shù)。

            這樣一來,只要我們改變傳進庫函數(shù)的參數(shù),就可以實現(xiàn)不同的功能,這樣有沒有覺得很靈活?并且當庫函數(shù)很復雜或者不可見的時候利用回調函數(shù)就顯得十分優(yōu)秀。

            3. 怎么使用回調函數(shù)?

            int Callback_1(int a)   ///< 回調函數(shù)1{
                printf("Hello, this is Callback_1: a = %d ", a);
                return 0;
            }
            int Callback_2(int b)  ///< 回調函數(shù)2{
                printf("Hello, this is Callback_2: b = %d ", b);
                return 0;
            }
            int Callback_3(int c)   ///< 回調函數(shù)3{
                printf("Hello, this is Callback_3: c = %d ", c);
                return 0;
            }
            int Handle(int x, int (*Callback)(int)) ///< 注意這里用到的函數(shù)指針定義{
                Callback(x);
            }
            int main(){
                Handle(4, Callback_1);
                Handle(5, Callback_2);
                Handle(6, Callback_3);
                return 0;
            }

            如上述代碼:可以看到,Handle()函數(shù)里面的參數(shù)是一個指針,在main()函數(shù)里調用Handle()函數(shù)的時候,給它傳入了函數(shù)Callback_1()/Callback_2()/Callback_3()的函數(shù)名,這時候的函數(shù)名就是對應函數(shù)的指針,也就是說,回調函數(shù)其實就是函數(shù)指針的一種用法。

            4. 下面是一個四則運算的簡單回調函數(shù)例子:

            #include <stdio.h>
            #include <stdlib.h>
            /****************************************
             * 函數(shù)指針結構體
             ***************************************/

            typedef struct _OP {
                float (*p_add)(floatfloat); 
                float (*p_sub)(floatfloat); 
                float (*p_mul)(floatfloat); 
                float (*p_div)(floatfloat); 
            } OP; 
            /****************************************
             * 加減乘除函數(shù)
             ***************************************/

            float ADD(float a, float b) {
                return a + b;
            }
            float SUB(float a, float b) {
                return a - b;
            }
            float MUL(float a, float b) {
                return a * b;
            }
            float DIV(float a, float b) {
                return a / b;
            }
            /****************************************
             * 初始化函數(shù)指針
             ***************************************/

            void init_op(OP *op){
                op->p_add = ADD;
                op->p_sub = SUB;
                op->p_mul = &MUL;
                op->p_div = &DIV;
            }
            /****************************************
             * 庫函數(shù)
             ***************************************/

            float add_sub_mul_div(float a, float b, float (*op_func)(floatfloat)){
                return (*op_func)(a, b);
            }
            int main(int argc, char *argv[]) {
                OP *op = (OP *)malloc(sizeof(OP)); 
                init_op(op);
                
                /* 直接使用函數(shù)指針調用函數(shù) */ 
                printf("ADD = %f, SUB = %f, MUL = %f, DIV = %fn", (op->p_add)(1.32.2), (*op->p_sub)(1.32.2), 
                        (op->p_mul)(1.32.2), (*op->p_div)(1.32.2));
                 
                /* 調用回調函數(shù) */ 
                printf("ADD = %f, SUB = %f, MUL = %f, DIV = %fn"
                        add_sub_mul_div(1.32.2, ADD), 
                        add_sub_mul_div(1.32.2, SUB), 
                        add_sub_mul_div(1.32.2, MUL), 
                        add_sub_mul_div(1.32.2, DIV));
                return 0
            }

            5. 回調函數(shù)實例

            一個GPRS模塊聯(lián)網(wǎng)的小項目,使用過的同學大概知道2G、4G、NB等模塊要想實現(xiàn)無線聯(lián)網(wǎng)功能都需要經(jīng)歷模塊上電初始化、注冊網(wǎng)絡、查詢網(wǎng)絡信息質量、連接服務器等步驟,這里的的例子就是,利用一個狀態(tài)機函數(shù)(根據(jù)不同狀態(tài)依次調用不同實現(xiàn)方法的函數(shù)),通過回調函數(shù)的方式依次調用不同的函數(shù),實現(xiàn)模塊聯(lián)網(wǎng)功能,如下:

            /*********  工作狀態(tài)處理  *********/
            typedef struct
            {

             uint8_t mStatus;
             uint8_t (* Funtion)(void); //函數(shù)指針的形式
            } M26_WorkStatus_TypeDef;  //M26的工作狀態(tài)集合調用函數(shù)
            /**********************************************
            ** >M26工作狀態(tài)集合函數(shù)
            ***********************************************/

            M26_WorkStatus_TypeDef M26_WorkStatus_Tab[] =
            {    
                {GPRS_NETWORK_CLOSE,  M26_PWRKEY_Off  }, //模塊關機
                {GPRS_NETWORK_OPEN,  M26_PWRKEY_On  }, //模塊開機
                {GPRS_NETWORK_Start,   M26_Work_Init  }, //管腳初始化
                {GPRS_NETWORK_CONF,  M26_NET_Config  }, /AT指令配置
                {GPRS_NETWORK_LINK_CTC,  M26_LINK_CTC  }, //連接調度中心  
                {GPRS_NETWORK_WAIT_CTC, M26_WAIT_CTC  },  //等待調度中心回復 
                {GPRS_NETWORK_LINK_FEM, M26_LINK_FEM  }, //連接前置機
                {GPRS_NETWORK_WAIT_FEM, M26_WAIT_FEM  }, //等待前置機回復
                {GPRS_NETWORK_COMM,  M26_COMM   }, //正常工作    
                {GPRS_NETWORK_WAIT_Sig,  M26_WAIT_Sig  },  //等待信號回復
                {GPRS_NETWORK_GetSignal,  M26_GetSignal  }, //獲取信號值
                {GPRS_NETWORK_RESTART,  M26_RESET   }, //模塊重啟
            }
            /**********************************************
            ** >M26模塊工作狀態(tài)機,依次調用里面的12個函數(shù)   
            ***********************************************/

            uint8_t M26_WorkStatus_Call(uint8_t Start)
            {
                uint8_t i = 0;
                for(i = 0; i < 12; i++)
                {
                    if(Start == M26_WorkStatus_Tab[i].mStatus)
                    {          
                  return M26_WorkStatus_Tab[i].Funtion();
                    }
                }
                return 0;
            }

            所以,如果有人想做個NB模塊聯(lián)網(wǎng)項目,可以copy上面的框架,只需要修改回調函數(shù)內部的具體實現(xiàn),或者增加、減少回調函數(shù),就可以很簡潔快速的實現(xiàn)模塊聯(lián)網(wǎng)。

            版權聲明:本文來源網(wǎng)絡,免費傳達知識,版權歸原作者所有。如涉及作品版權問題,請聯(lián)系我進行刪除。


            關鍵詞: 編程 函數(shù)

            評論


            技術專區(qū)

            關閉