C語言函式指標與回撥用函式

lixiaogang_theanswer發表於2018-05-22

1. 函式指標
指標是c語言的精髓,同時也是c語言中比較深奧、比較難掌握的一個知識點。本質上,對於一個記憶體單元來說,單元的地址即為指標, 其中存放的資料才是該單元的內容。我們允許用一個變數來存放指標,這種變數稱為指標變數。因此, 一個指標變數的值就是某個記憶體單元的地址或稱為某記憶體單元的指標。下面定義了幾種不同型別的指標變數。

char *pTr = NULL;
int *pT = NULL;
double *pDou = NULL;

其中:pTr是指向 char 型型別的指標變數;pT是指向 int 型別的指標變數;pDou 是指向double 型別的指標變數。指標變數是由普通型別派生出來的一種型別,其中變數前面的 * 號用於表明該資料型別是指標型別。

1.1 何為函式指標?
在c語言中有4個概念是值得弄清楚的,分別是:函式指標、指標函式、陣列指標和指標陣列。
我這裡簡單的對這4個概念做一下說明:
函式指標:
它是一個指標,該指標存放的是一個函式的地址,而函式的名稱就該函式的入口,即地址。如: void (*pFunc) ( int a);
指標函式:
指帶指標的函式,即本質是一個函式。(函式四要素:函式返回型別、函式名、函式引數型別、函式引數個數);指標函式返回指向某種型別指標(地址)的函式。int * pFunc(int a);
陣列指標:
它是一個指標,它指向一個陣列。在32 位系統下永遠是佔4 個位元組,至於它指向的陣列佔多少位元組,不知道。它是“指向陣列的指標”的簡稱。
如:int (pTr) [10];
指標陣列:
首先它是一個陣列,陣列的元素都是指標,陣列佔多少個位元組由陣列本身決定。它是“儲存指標的陣列”的簡稱。如: int
pTr[ 10];

通過上面的描述知道:函式指標是一個指標,只是該指標中存放的是函式的地址。函式是有地址的,系統會在棧上為其分配記憶體空間,供函式中的變數使用。通過函式的記憶體地址定址,便可找到該函式並呼叫。

程式碼1

/*************************************************************************
 * File Name: FuncPointer.cpp
 * Author:    The answer
 * Function:  Other        
 * Mail:      2412799512@qq.com 
 * Created Time: 2018年05月22日 星期二 00時41分31秒
 ************************************************************************/

#include <iostream>
#include <stdio.h>
using namespace std;

void func(int a)
{
    cout<<"a is ["<<a<<"]"<<endl;
}

int main(int argc,char **argv)
{
    int a = 66;
    func(66);
    printf("func address [%p]\n",func);
    return 0;
}

結果:
a is [66]
func address [0x4008ed]
通過程式碼可以看到函式也是有其地址的。

1.2 如何定義函式指標?
程式碼2

/*************************************************************************
 * File Name: pointer.cpp
 * Author:    The answer
 * Function:  Other        
 * Mail:      2412799512@qq.com 
 * Created Time: 2018年05月22日 星期二 00時46分23秒
 ************************************************************************/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

int addFunc(int a,int b)
{
    return a+b;
}

int main(int argc,char **argv)
{
    int (*pTr)(int a,int b) = addFunc;
    int (*pTR)(int a, int b) = &addFunc;

	//函式指標指向函式地址時候,可以加取地址符號&,也可以不加,效果等同。

    printf("pTr[%p]\n pTR[%p]\n addFunc[%p] \n",addFunc,*pTr,*pTR);
    return 0;
}

在程式碼2中定義了函式指標變數 pTr 和 pTR, 同時分別指向函式addFunc,也就是說這2個指標變數的值都是這個函式的地址。其列印結果為:
pTr[0x40070d]
pTR[0x40070d]
addFunc[0x40070d]
從結果看到它們都是執行了同一個地址。

1.2.1 函式指標的兩種定義方式

方法1:(1)void (*pTr)(int ,int, double) = NULL;
方法2:(2)typedef void (*pTr)(int, int, double);
pTr pPointer = NULL;
這兩種方式都是定義了一個指向返回值為 void 型別,引數為 (int, int, double) 的函式指標。第二種方法是為了讓函式指標更容易理解,尤其是在複雜的環境下;而對於一般的函式指標,直接用第一種方法就行了。

程式碼3:

/*************************************************************************
 * File Name: pPtr.cpp
 * Author:    The answer
 * Function:  Other        
 * Mail:      2412799512@qq.com 
 * Created Time: 2018年05月22日 星期二 01時20分25秒
 ************************************************************************/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
using namespace std;

void sigHandler(int signum)
{
    printf("signum[%d]\n",signum);
    exit(0);
}

int main(int argc,char **argv)
{
    while(true)
    {
        printf("in main func....\n");
        signal(SIGINT,sigHandler);
        signal(SIGHUP,sigHandler);
        sleep(1);
    }

    printf("End of the function.\n");
    return 0;
}


#if 0
   typedef void (*sighandler_t)(int);
   sighandler_t signal(int signum, sighandler_t handler);
#endif

關於signal的詳細用法
程式碼3 中使用了signal訊號捕捉函式,Linux下的signal就是一個回撥函式,其實在linux下類似這樣的函式還有很多。

2. 回撥函式
百度百科對回撥函式定義:
回撥函式就是一個通過函式指標呼叫的函式。如果你把函式的指標(地址)作為引數傳遞給另一個函式,當這個指標被用來呼叫其所指向的函式時,我們就說這是回撥函式。回撥函式不是由該函式的實現方直接呼叫,而是在特定的事件或條件發生時由另外的一方呼叫的,用於對該事件或條件進行響應。

從上面的定義中,提取重要的資訊:
① 函式指標作為另一個函式的引數
② 回撥函式不是由函式實現方直接呼叫
③ 特定事件或條件發生由另一方呼叫

程式碼4

/*************************************************************************
 * File Name: CallBackFunc.c
 * Author:    The answer
 * Function:  Other        
 * Mail:      2412799512@qq.com 
 * Created Time: 2018年05月22日 星期二 01時36分11秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void  addFunc(int a,int b)
{
  printf("sum is [%d]\n", a+b);
  return;
}

typedef void (*pTr)(int a,int b);
void func(int a,int b,pTr pointer)
{
   pointer(a,b);
    return;
}

int main(int argc,char **argv)
{   
    int a = 66,b = 88;
    func(a,b,addFunc);
    return 0;
}

列印結果:
sum is [154]

程式碼4 中簡單的描述了回掉喊的使用,該程式中將指向void (*)(int a,int b);型別的指標變數pTr作為引數傳給func函式,最終求得a、b的和。


博主最新開了一個網店[ 華少潮牌男裝店 ],款式多樣,價格實惠,質量保證。歡迎各位讀者進店檢視。購買時請說明是CSDN讀者,優惠更大。期待你的光臨!!!
在這裡插入圖片描述

相關文章