C函数指针与回调函数

参考链接:C 函数指针与回调函数 | 菜鸟教程

函数指针

函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针变量的声明:
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

实例

以下实例声明了函数指针变量 p,指向函数 max:

#include 
 
int max(int x, int y)
{
    return x > y ? x : y;
}
 
int main(void)
{
    /* p 是函数指针 */
    int (* p)(int, int) = & max; // &可以省略
    int a, b, c, d;
 
    printf("请输入三个数字:");
    scanf("%d %d %d", & a, & b, & c);
 
    /* 与直接调用函数等价,d = max(max(a, b), c) */
    d = p(p(a, b), c); 
 
    printf("最大的数字是: %d\n", d);
 
    return 0;
}

编译执行,输出结果如下:

请输入三个数字:1 2 3
最大的数字是: 3

回调函数

函数指针作为某个函数的参数

函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
简单讲:回调函数是由别人的函数执行时调用你实现的函数。
以下是来自知乎作者常溪玲的解说:

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,
店员就打了你的电话,然后你接到电话后就到店里去取了货。
在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,
店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。

实例

实例中 populate_array() 函数定义了三个参数,其中第三个参数是函数的指针,通过该函数来设置数组的值。
实例中我们定义了回调函数 getNextRandomValue(),它返回一个随机值,它作为一个函数指针传递给 populate_array() 函数。
populate_array() 将调用 10 次回调函数,并将回调函数的返回值赋值给数组


#include   
#include 
 
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
    for (size_t i=0; i

编译执行,输出结果如下:

1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421

else

  • size_t 是一种数据类型,近似于无符号整型,但容量范围一般大于 int 和 unsigned。这里使用 size_t 是为了保证 arraysize 变量能够有足够大的容量来储存可能大的数组。

  • size_t 类型在C语言标准库函数原型使用的很多,数值范围一般是要大于int和unsigned.
    但凡不涉及负值范围的表示size取值的,都可以用size_t;比如array[size_t]。
    size_t 在stddef.h头文件中定义。
    在其他常见的宏定义以及函数中常用到有:
    1,sizeof运算符返回的结果是size_t类型;
    2,void *malloc(size_t size)…

  • 补充下带参的回调函数:

#include 

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

//sum2是回调函数,通过函数指针*p回调sum函数
int sum2(int num,int (*p)(int,int),int a,int b){
    return  num * p(a,b);
}

int main()
{
    int (* p)(int a,int b)=sum;

    printf("SUM=%d\n",p(1,2));
    printf("SUM2= %d\n",sum2(2,sum,1,2));
    return 0;
}

在内存中除了存放各种各样的变量之外,函数在编译时也会被存放至内存中,因此函数指针就是指向一个函数的指针。

函数指针可以实现回调函数的操作,下面列举一些常用的函数指针操作:

// 函数指针示例 
#include 
#include 

// 几个示例函数 
void print() {
	printf("哈哈哈\n"); 
} 

void print1() { 
	printf("哈哈哈哈哈哈\n"); 
}
 
int sum(int a, int b) { 
	return a + b; 
}

void printInt(int a) { 
	printf("%d ", a); 
} 

int *pointer() { 
    int *a = (int *)malloc(sizeof(int)); 
    *a = 11; 
	return a; 
} 

// 把函数指针作为函数参数传递(回调函数) 
// 函数声明(注意类型的表示) 
void traverse(int[], void (*)(int)); 
/// @brief 遍历数组元素(回调函数例子) 
/// @param array 数组 
/// @param callback 回调函数,无返回值,一个int参数 
void traverse(int array[], void (*callback)(int)) { 
    // 遍历前面3个用回调函数访问 
    int i; 
    for (i = 0; i < 3; i++) { 
        callback(array[i]); 
    } 
    printf("\n"); 
}

// 函数返回函数指针 
// 返回一个返回值为int,带两个int参数的函数指针
// 函数本身名为fun,本身无参数 
int (*fun())(int, int) { 
	return sum; 
} 
// 函数返回函数指针,带参数型 
// 返回一个返回值为void,不带参数的函数指针 
// 函数本身名为fun1,带一个int参数 
void (*fun1(int a))() { 
	if (a == 1) 
		return print1; 
	return print; 
} 

int main() { 
    // 函数指针p:无参,返回类型void 
    // 让函数指针p指向print函数 
    void (*p)() = print; 
    //执行p 
    p(); 

    // 函数指针sp:两个int参数,返回类型int 
    // 让函数指针sp指向sum函数 
    int (*sp)(int, int) = sum; 
    // 执行sp 
    printf("%d\n", sp(1, 2)); 

    // 一个返回类型为指针的函数指针 
    // 把pointer赋值给函数指针ip 
    int *(*ip)() = pointer; 
	printf("%d\n", *ip()); 
    
	// 一个长度为2的函数指针数组fp[2],其中函数指针是void无参函数 
    void (*fp[2])(); 
    // 给函数指针数组中元素赋值 
    fp[0] = print; 
	fp[1] = print1; 
    // 执行它们 
    fp[0](); 
	fp[1](); 
    
	// 使用回调函数 
    int arr[] = {1, 2, 3}; 
	traverse(arr, printInt); 

    // 执行返回函数指针的函数得到函数指针,将函数返回值赋值给函数指针getSum 
    int (*getSum)(int, int) = fun(); 
    printf("%d\n", getSum(3, 4)); 
    
	// 传参的返回函数指针的函数,下面两个分别赋值给函数指针pp1,pp2 
    void (*pp1)() = fun1(1); void (*pp2)() = fun1(0); 
    // 执行 
    pp1(); 
    pp2(); 
    
	// 输出函数指针类型变量的大小,可见使用"返回值 (*)(参数)"可以表示一个函数指针类型的指针变量 
    printf("%ld %ld %ld\n", sizeof(void (*)()), sizeof(void (*)(int)), sizeof(int (*)())); return 0; 
}

运行结果:

哈哈哈
3
11
哈哈哈
哈哈哈哈哈哈
1 2 3
7
哈哈哈哈哈哈
哈哈哈
8 8 8

你可能感兴趣的:(C/C++,c语言)