函数指针的使用详解
函数指针是C++中经常用到的指针类型,对业务解耦合有着重要的意义,学习函数指针,首先应该学习数组类型,两者在定义上大同小异,所以,先来回顾一下数组类型的用法吧!
1 数组类型
数组类型的使用主要涉及三个定义:
- 如何定义一个数组类型
- 如何定义一个数组指针类型
- 如何定义一个指向数组类型的指针变量
我在代码中详细注释了数组类型、数组指针类型以及指向数组类型的指针变量的定义方法,如下:
#include <stdio.h>
#include <string.h>
#include "stdlib.h"
int main()
{
//定义一个数组 int array[10]
//定义一个数组类型
typedef int (MyArrayType)[10];
//用这个类型定义一个变量
MyArrayType array0;//相当于 int array[10];
array0[0] = 2;
//定义一个数组指针类型
int array1[10];
typedef int (*PMyArrayType)[10];
PMyArrayType pmyArray;
pmyArray = &array1;
(*pmyArray)[0] = 3;
//定义一个指向数组类型的指针变量
int array2[10];
int (*pMyArray)[10]; //告诉编译器分配四个字节的内存
pMyArray = &array2;
(*pMyArray)[0] = 4;
//打印结果
printf("数组类型输出:%d\n", array0[0]);
printf("数组指针类型输出:%d\n", array1[0]);
printf("指向数组类型指针变量输出:%d\n", array2[0]);
return 0;
}
输出结果如下图:
2 函数指针
同数组类型相似,函数指针也是三个定义:
- 如何定义一个函数类型
- 如何定义一个函数指针类型
- 如何定义一个指向函数的指针变量
同上,代码中详细注释了这三种定义方法及它们的使用方法,如下:
#include <stdio.h>
#include <string.h>
#include "stdlib.h"
//test是函数名,函数名是函数首地址,函数名就是函数指针
//对函数地址取多少次地址结果都还是函数地址
int test(int a)
{
printf("a=%d\n",a);
return 0;
}
int main()
{
//定义一个函数类型
typedef int (MyFuncType)(int);
MyFuncType *myfunc = test;
printf("输出函数类型:");
(*myfunc)(2);
//定义函数指针类型
typedef int (*PMyFuncType)(int);
PMyFuncType pmyFunc = test;
printf("输出函数指针类型:");
(*pmyFunc)(3);
//定义一个指向函数的指针变量
int (*PmyFunc)(int); //告诉编译器分配四个字节
PmyFunc = test;
printf("输出指向函数指针类型指针变量:");
(*PmyFunc)(4);
return 0;
}
输出结果如下图:
3 函数指针作函数参数
函数指针作函数参数是函数指针最重要的使用,通过一段代码来学习,如下:
#include <stdio.h>
#include <string.h>
#include "stdlib.h"
int add(int a, int b)
{
int c;
c = a + b;
return c;
}
int MyPrint(int (*pMyAdd)(int,int))
{
printf("函数指针作函数参数:%d\n", pMyAdd(2,3));
}
//声明一个函数指针类型
//函数指针作函数参数不光把函数的入口地址给了被调函数,同时作了接口的约定
typedef int (*PMyFuncType)(int,int);
int MyPrint1(PMyFuncType pMyFunc)
{
printf("函数指针作函数参数:%d\n", pMyFunc(7,8));
}
int main()
{
//定义一个函数指针变量
int (*pAdd)(int,int);
pAdd = add;
//MyPrint方法
MyPrint(pAdd);
//MyPrint1方法
MyPrint1(pAdd);
return 0;
}
输出结果如下图:
函数指针作函数参数最重要的目的就是解耦合,即将写任务和调用任务的人分开,它的使用一般有两种情况,称为函数指针的正反向调用。
- 正向调用:应用程序EXE调用动态库
- 反向调用:动态库反向调用应用程序,在动态库中通过函数指针实现业务模型的抽象
以动态库为例重点说明一下反向调用的使用方法,主要分为两步:
- 动态库提前定义业务模型接口
- 提前把应用层的函数入口地址注入到动态库
比如在动态库中抽象一个加密模型,如下:
typedef int (*EncData)(unsigned char *inData, int inDataLen, unsigned char *outData, int outDataLen, void *Ref, int RefLen);
然后只需要在动态库中调用此函数,而这个函数的真实实现由应用层完成,应用层将函数地址和参数传递给动态库即可,通过这种解耦合的方法,当业务需求发生更改时,就无需再次改动动态库。
以上。