C语言函数指针与回调用函数

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:      [email protected] 
 * 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:      [email protected] 
 * 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:      [email protected] 
 * 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:      [email protected] 
 * 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的和。

猜你喜欢

转载自blog.csdn.net/lixiaogang_theanswer/article/details/80400259
今日推荐