函数指针
* 函数指针和指针函数
1. 指针函数:它本身还是一个函数,只不过函数的返回值是一个指针
2. 函数指针:它是一个指针,指针指向的是一个函数的入口
指针函数常用定义形式为ret* func(args);
其中,func是一个函数,args是形参列表,ret *作为一个整体,是 func函数的返回值,是一个指针的形式。下面举一个具体的实例来做说明:
# include <stdio.h>#
include <stdlib.h>
int * func_sum(int n){
static int sum = 0;
int *p = ∑
for (int i = 0; i < n; i++){
sum += i;
}
return p;
}
int main(void){
int num = 0;
printf("please input one number:");
scanf("%d", &num);
int *p = func_sum(num);
printf("sum:%d\n", *p);
return 0;
}
上例就是一个指针函数的例子,其中,int * func_sum(int n)就是一个指针函数,
其功能十分简单,是根据传入的参数n,来计算从0到n的所有自然数的和,其结果通过指针的形式返回给调用方。
tips:上述代码我们的sum变量加上了修饰关键词static,这是因为函数的参数值和局部变量是存储在栈区的,在这个函数结束后我们的编译器也就会自动释放这块栈区,那个这个函数内部的局部变量和参量值都会被销毁。如果我们的p指针指向的是一个局部变量sum,那么问题也就来了。在函数结束后,变量sum的内存空间就被释放了,可能都已经被别的变量给替代了,那个我们在main函数中调用函数func_sum返回的地址还能用吗?
答案是不能用,但是如果我们把sum变量改成int sum=0,然后调试,在main函数中又可能就不会出现这个问题。为什么这个问题会不出现呢?因为编译器可能会帮你把这个变量保存一段时间,如果一段时间没用它才会再被释放,所以我们也可实验:如果在函数调用后再立即访问这段空间,这段空间的内容可能不会变,但如果我们等待一段时间再访问这块内存空间,就会有不一样的结果。
函数指针常用定义形式
ret (*func_p)(args)
其中,ret为返回值,*p作为一个整体,代表的是指向该函数的指针,args为形参列表。其中p被称为函数指针变量 。
*** tips: (* func_p)的这个括号()是必不可少的。**
这和我们的运算优先级和结合性有关,()的运算优先级高于*,如果我们不加(),func_p就会优先结合()成为一个函数。
我们再来用一些稍微复杂的东西来说明这个知识点。
double *(*p1)(double *,int)
double *(*pa[3])(douuble*,int)
1. 第一个是一个返回值为double *,参数为double *和int的一个函数指针
2. 第二个是一个函数指针数组,每个指针的返回值都是double *,参数为double *和int。[]运算符优先级高于*,pa先和[]结合表示这是一个数组。随后和*结合表示这是一个指针数组。二个()的优先级相同,但是()的结合性是左结合性,所以(* pa[[3])优先于后面的参数列表结合,表明这是一个函数指针
函数指针的初始化和调用 和数组类型,函数名代表这函数的入口地址,所以函数指针的初始化比较简单函数指针名=函数名;我们用一个简单的例子来说明它的初始化和调用方法
#include <stdio.h>
#include <stdlib.h>
int func(int a,int b){
int final;
final = a + b;
printf("the final = %d\n", final);
return final;
}
int main(){
int (*function_p)(int, int);
function_p = func;//初始化
(*function_p)(1, 2);//二种调用方法
function_p(2, 3);
return 0;}
*** 回调函数**
函数指针一个非常典型的利用就是回调函数什么是回调函数?回调函数就是一个通过函数指针调用的函数。他将函数指针作为一个参数,传递给另外一个函数。回调函数并非由实现方直接调用,而是在特定的事件或条件发生时由另一方直接调用的。我们可以看一个回调函数的例子。
#include<stdio.h>
#include<stdlib.h>
//函数功能:实现累加求和
int func_sum(int n)
{
int sum = 0;
for (int i = 0; i < n; i++){
sum += i;
} return sum;}//这个函数是回调函数,其中第二个参数为一个函数指针,通过该函数指针来调用求和函数,并把结果返回给主调函数
int callback(int n, int (*p)(int))
{
return p(n);}int main(void){
int n = 0;
printf("please input number:");
scanf("%d", &n);
printf("the sum from 0 to %d is %d\n", n, callback(n, func_sum)); //此处直接调用回调函数,而不是直接调用func_sum函数
return 0;
}
上面这个简单的demo就是一个比较典型的回调函数的例子。在这个程序中,回调函数callback无需关心func_sum是怎么实现的,只需要去调用即可。这样的好处就是,如果以后对求和函数有优化,比如新写了个func_sum2函数的实现,我们只需要在调用回调函数的地方将函数指针指向func_sum2即可,而无需去修改callback函数内部
* typedef和函数指针的综合应用
typedef void (* TaskFunction_t)( void * );
在这样定义之后,我们就可以直接用TaskFunction这个别名来代指 void (* )(void *)类型的函数指针