對於函數指針和typedef的結合運用


  實質:函數指針實質是一個指針,並不是函數,函數有自己的函數體,而指針只是一個變量

  指針函數和函數指針的區別:

     指針函數: 實質:是一個函數,有自己的函數體

           格式:數據類型關鍵字 *xxx(形參)

              {

                  函數體;

              }

     函數指針: 實質:是一個指針,一個變量,常用來調用函數

           格式:數據類型關鍵字 *指針名)(形參)

 

  功能:指向函數的指針可用於調用它所指向的函數。可以不需要使用解引用操作符,而直接通過指針調用此函數。

  示例1:

      typedef void FUN (char , int);

      void (*pf)(char, int);//聲明一個函數指針pf,指向一個返回值為0帶有(char,int)兩個形參的函數

      FUN fun; //實際就是聲明一個void fun(char,int)的函數

      pf=fun;

  兩種調用方法如下:

      (*pf)('c',90); // 顯式調用

      pf('c',90); // 隱式調用

  示例 2:通過指針調用函數

1. #include <stdio.h>2.3.
2. // 聲明一個函數指針,指向的函數形參帶有一個char類型,一個int類型,返回類型為 void
3. void (*pf)(char, int);
5. // 聲明一個函數,形參為一個 char 類型,一個 int 類型,返回類型為 void
6. void fun(char ,int);
7. int main()
8. {
9.     pf=fun; //函數指針 pf 賦值為 fun 函數的地址(函數名代表函數的地址)
10.    (*pf)('c',90); //調用 pf 指向的函數
11.    pf('a',80);
12. }
13. void fun(char a,int b)
14. {
15.    printf("the argument is %c and %d\n",a,b);
16. }

  運行結果: the argument is c and 90

       the argument is a and 80

  返回指向函數的指針
  函數可以返回指向函數的指針,但是,正確寫出這種返回類型相當不容易,例如:
     int (*ff(int))(int*,int);
  要理解函數指針聲明的最佳方法是從聲明的名字開始由里而外理解。要理解該聲明的含義,首先觀察“ff(int)”
  是將 ff 聲明為一個函數,它帶領有一個 int 型的形參。該函數返回“int (*)(int*,int)”它是一個指向函數的指針,所指向的函數返回 int 型並帶有兩個分別為 int *型和 int 型的形參。
  使用 typedef 可使該定義更簡明易懂:
    typedef int (*PF)(int *,int);
    PF ff(int);
  示例:  

#include <iostream>
using namespace std;
typedef void (*callback)(int x);            // 定義一個函數指針類型
void myFunc1(int x)                         // myFunc1 的聲明要與callback一樣
{
    cout << "This is myFunc1 " << x << endl;
}
void myFunc2(int x)
{
    cout << "This is myFunc2 " << x << endl;
}
void callMyFunc(callback cb, int x)      // 把函數指針類型當做調用函數參數類型
{
    cb(x);
}
int main()
{
    callMyFunc(myFunc1, 1);
    callMyFunc(myFunc2, 2);
    return 0;

}

 下面舉幾個typedef和函數指針結合使用的例子:

    

 

  左邊第一個運行出錯 右邊兩個正確

  出錯原因:

  typedef定義的pf是一種void (*)(int)的函數指針類型,pf定義的是指針(它是一個數據類型關鍵字,類似於int)。

  用pf去聲明fun肯定會出錯,pf fun,是定義fun為一個函數指針變量(可以理解為函數名),而不是聲明函數,右邊兩個是正確的。

  函數名是可以作為函數指針變量,作為函數的入口地址,但是函數名不僅僅是這種作用。

  函數名相當於表示函數的入口地址,我們調用時通過函數名,讓程序跳轉到對應函數處開始執行

  

  還可這樣使用:

  void (*signal(int signum,void(* handler)(int)))(int); 等價於下面兩行

  typedef void (*sighandler_t)(int);

  sighandler_t  signal(int signum,sighandler_t handler)

   

  運行結果: fdsfsfsf1
        fdsfsfsf3

   

  解剖一下signal函數,理解函數指針和typedef

void (*signal(int signum,void(* handler)(int)))(int); 等價於下面兩行 typedef void (*sighandler_t)(int); sighandler_t signal(int signum,sighandler_t handler)

  分析:先分析第一行,看到這一串的函數聲明,不要慌,從內而外一點一點分析:

     1. signal(int signum,void(* handler)(int))這是一個函數,函數名為signal

       (1) 第一個形參:int signum,是一個整形變量;

       (2) 第二個形參:void(*handler)(int),這是一個函數指針,指向:返回值為void型,且帶一個int型的形參的函數。

          也就是說,這個形參,是一個指針,或者說是一個地址,可以理解為這個形參是函數名,因為函數名是函數的入口

         地址。里面分析完了。

     2. signal函數的外面是 void(*)(int),想一想,在定義或者聲明函數的時候,都需要說明函數返回值的類型,這個signal

       函數的形參已經明確了,但是返回值還不知道,這個void(*)(int)就是返回值類型,這個類型是一個函數指針,碰巧的是,

       這個函數指針指向的函數類型和signal的第二個形參指向的類型相同,都是指向:返回值為空,且帶一個int類型形參的函數。

      3. 因此先用typedef定義一種數據類型,這個類型就是void(*)(int),將這種類型定義為,或者說是起名別,叫做sighandler_t

       sighandler_t = void(*)(int),所以可以將void(*)(int)類型的函數,在聲明或者定義的時候用sighandler_t。

     4. signal函數返回值為void(*)(int)型,用sighandler_t代替,第2個形參是void(*)(int)型,用sighandler_t代替。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM