1.函数指针
我们知道,整型指针是指向整型的指针;数组指针是指向数组的指针;以此类推,那么 函数指针就是指向函数的指针。
和其他指针一样,在讲解函数指针之前,首先明白这三点:
1.( )的优先级高于 *
2.定义一个变量是,除去变量名,剩下的就是它的变量类型
3.一个指针变量去除变量名和 * 剩下的就是指针指向的内容的类型
对于函数指针,举个栗子:
#include<stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int(*p)(int, int) = &Add;//取出函数的地址放在函数指针p中
return 0;
}
此时的变量 p 就为一个函数指针变量。
那么如何定义函数指针的呢?图示如下:
即定义一个函数指针时,指针的类型要与函数的类型一致。
例如
void test ( char* str ) 为一个函数,那么定义一个指向它的函数指针就为:
void ( * p ) ( char * )
补充说明一点:
对于数组而言: 数组名 != &数组名
对于函数而言: 函数名 = &函数名( 规定)
那么如何使用函数指针呢?
看如下代码:
int add(int x, int y)
{
return x + y;
}
int main()
{
int (*p)(int, int) = &add;
int ret = (*p)(3, 5);//对p解引用,然后再传入参数即可
printf("%d\n", ret);
return 0;
}
即通过对函数指针解引用找到该函数,然后传入参数就可实现函数的调用。
深入探究:
对于 int (*p)(int, int) = &add; 此行代码,我们又知道 函数名 = &函数名,
那么代码也可写成 int (*p)(int, int) = add; 因为指针p中存放的为函数add的地址,所以我们就能这样理解:p == add ,即 p 与函数名 add 为一回事,所以当我们调用函数时,可以写:
add ( a , b ) == p ( a , b ) == (*p) ( a , b ) ---- 经过代码验证,输入的结果一样。
这样一来,我们就知道了 ( *p ) ( 3, 5) 中的 解引用符号 * 是没有任何意义的,在写程序时,可写可不写。
2.函数指针数组
我们知道,数组是一个存放相同数据类型的空间,例如:
int arr[ 10 ] 为一个整型数组,存放10个元素,每个元素 int 型整数
char* arr[ 10 ] 为一个指针数组,存放10 个元素,每个元素为 char* 型指针
. . .
那么如果要将函数指针存放在一个数组中,那么这个数组就为函数指针数组
如何定义函数指针数组?例如:
定义 int (*parr[10])( int , int )
parr[10] 就为一个函数指针数组,可以存放10个函数指针,每个函数指针的类型为 int (* )( int , int ) 型。
所以简单来说,创建一个函数指针,只需要在原有的函数指针的形式下加上
[ ] 即可,例如:
存在函数指针:int (*p)(int, int) = &add
此时要创建一个存放指针 p 的数组,那么函数指针数组定义为:
int ( * parr[10] )( int , int )
该函数指针数组能存放 10 个与指针p类型一样的函数指针
函数指针数组的应用:转移表
举个栗子:模拟计算器
int add(int x, int y)
{
return x + y;
}
int sub(int x, int y)
{
return x - y;
}
int mul(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}
int main()
{
int input = 1;
int (*p[5])(int, int) = { 0,add, sub, mul,div };
while (input)
{
printf("************************\n");
printf("** 1.add 2.sub **\n");
printf("** 3.mul 4.div **\n");
printf("************************\n");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
int i = 0;
int j = 0;
printf("请输入运算数:");
scanf("%d %d", &i, &j);
int ret = (*p[input])(i,j);
printf("结果为:%d\n", ret);
}
else
{
printf("输入错误!\n");
}
}
return 0;
}
这里就巧妙地运用了函数指针数组,将运算的函数存放在函数指针数组p中,
再通过数组的下标找到相应函数,解引用后传参就可调用相应函数。
相比于switch-case语句来每次调用函数,使用函数指针数组更为方便,且代码量相对少,避免代码冗余。
3.指向函数指针数组的指针
说明:
指向函数指针数组的指针是一个 指针,
该指针指向一个 数组 ,数组的元素都是 函数指针 ;
如何定义?
void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
void (*pfun)(const char*) = test;//函数指针 pfun
void (*pfunArr[5])(const char* str);//函数指针数组 pfunArr
pfunArr[0] = test;
void (*(*ppfunArr)[10])(const char*) = &pfunArr;
//指向函数指针数组 pfunArr 的指针 ppfunArr
return 0;
}
void ( * ( * ppfunArr )[10])(const char*) = &pfunArr; 即为指向函数指针数组的指针 ppfunArr 的定义
对于指向函数指针数组的指针的讲解就不多说了,仅作了解即可。
4.回调函数
所谓回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
举个简单的栗子:
void test2()
{
printf("Hello world!");
}
void test1(void (*p)()) //形参用函数指针接收,该指针指向 test2
{
p(); //调用函数指针
}
int main()
{
test1(test2); //将函数test2作为参数,即将函数test2的地址传过去
return 0;
}
类似以上程序中函数的调用机制就很好的利用了回调函数。
回调函数的意义就在于可以通过一个函数从而实现多个函数的调用,可以有效的减少代码冗余的出现。
回调函数机制的运用在这里先不做说明,我会在下一篇博客中做具体详解。
希望大家多多关注哦!!!