函数指针
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针类型的声明:
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
实例
以下实例声明了函数指针变量 p,指向函数 max:
实例
#include <stdio.h>
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 <stdlib.h>
#include <stdio.h>
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
for (size_t i=0; i<arraySize; i++)
array[i] = getNextValue();
}
// 获取随机值
int getNextRandomValue(void)
{
return rand();
}
int main(void)
{
int myarray[10];
/* getNextRandomValue 不能加括号,否则无法编译,因为加上括号之后相当于传入此参数时传入了 int , 而不是函数指针*/
populate_array(myarray, 10, getNextRandomValue);
for(int i = 0; i < 10; i++) {
printf("%d ", myarray[i]);
}
printf("\n");
return 0;
}
编译执行,输出结果如下:
16807 282475249 1622650073 984943658 1144108930 470211272 101027544 1457850878 1458777923 2007237709
ElleryQ
844***495@qq.com
参考地址
有关于 size_t:
size_t 是一种数据类型,近似于无符号整型,但容量范围一般大于 int 和 unsigned。这里使用 size_t 是为了保证 arraysize 变量能够有足够大的容量来储存可能大的数组。
ElleryQ
844***495@qq.com
参考地址
fwfdjq23
fwf***23@163.com
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)...
fwfdjq23
fwf***23@163.com
钢板
sim***php@163.com
更标准写法 GCC 直接能过,指针变量用指针变量的方式处理。
#include <stdlib.h> #include <stdio.h> // 回调函数 void populate_array(int *array, int arraySize, int (*getNextValue)(void)) { int i; for(i=0; i<arraySize; i++){ *(array+i) = getNextValue(); } } // 获取随机值 int getNextRandomValue(void) { return rand(); } int main(void) { int myarray[10]; int i; populate_array(myarray, 10, getNextRandomValue); for(i=0; i<10; i++) { printf("%d ", myarray[i]); } printf("\n"); return 0; }钢板
sim***php@163.com
神奇杨半仙
227***4534@qq.com
引用这段话:你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
可以这样理解,号码就是回调函数的名称,手机就是函数指针,有手机有了号码,就可以进行回调。
神奇杨半仙
227***4534@qq.com
菜鸟程序员
a74***7961@qq.com
补充下带参的回调函数:
#include <stdio.h> int sum(int a,int b){ return a+b; } //sum2回调sum函数 int sum2(int num,int (*sum)(int,int),int a,int b){ return num * sum(a,b); } int main() { int (* p)(int a,int b)=sum; printf("SUM=%d\n",sum(1,2)); printf("SUM2= %d\n",sum2(2,sum,1,2)); return 0; }菜鸟程序员
a74***7961@qq.com
栗子
and***_e@163.com
参考地址
关于回调函数的一点思考
在 A 函数中将参数与 C 函数传递给 B 函数,B函数调用 C 函数;B 函数调用的动作称为回调,C 函数称为回调函数。
举栗
#include <stdio.h> // 回调函数a void callback_a(int var_a){ printf("Call callback_a, var: %d\n\n", var_a); } // 回调函数b void callback_b(int var_b){ printf("Call callback_b, var: %d\n\n", var_b); } // 回调动作 void callback_act(int x, void (*callback) (int var)){ printf("Call callback_act, var_x: %d\n\n", x); callback(x); } void main(){ int a = 1, b = 2; callback_act(a, callback_a); callback_act(b, callback_b); printf("Main program has done."); }执行结果:
仔细想想回调函数的作用完全可以通过普通函数来达到,其实回调函数最大的意义在于解耦,降低了代码之间的耦合度。
栗子
and***_e@163.com
参考地址
jave.lin
lin***008@126.com
关于 size_t,我在:vcruntime.h 看到如下定义:
// Definitions of common types #ifdef _WIN64 typedef unsigned __int64 size_t; typedef __int64 ptrdiff_t; typedef __int64 intptr_t; #else typedef unsigned int size_t; typedef int ptrdiff_t; typedef int intptr_t; #endif也就是说会判断你的机器是否 64 位,如果是:
如果不是:
所以总结得说,就是根据系统位数来或是对应的 64 位 int 还是 32 位的 int。
jave.lin
lin***008@126.com
xuxing
176***6295@qq.com
@5楼的代码这样改才能体现回调函数:
#include <stdio.h> 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; }xuxing
176***6295@qq.com
守望时空33
yan***hui2001a@163.com
在内存中除了存放各种各样的变量之外,函数在编译时也会被存放至内存中,因此函数指针就是指向一个函数的指针。
函数指针可以实现回调函数的操作,下面列举一些常用的函数指针操作:
// 函数指针示例 #include <stdio.h> #include <stdlib.h> // 几个示例函数 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); // 执行sp printf("%d\n", sum(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("%d %d %d\n", sizeof(void (*)()), sizeof(void (*)(int)), sizeof(int (*)())); return 0; }运行结果:
守望时空33
yan***hui2001a@163.com
笨鸟先废
273***2295@qq.com
关于 @5 楼和 @8 楼进行思考和修改的个人观点如下:
#include <stdio.h> int sum(int num1, int num2){ return num1 + num2; } //sum2调用sum函数 int sum2(int num3, int (*shapePara)(int, int), int num4, int num5){ /* shapePara形式--函数参数名,名字不重要(与sum函数一致,亦可), 实际的指向关系是shapePara --> callback_sum(可省,详见下面多行注释) --> sum,调用sum函数里面的功能; */ return num3 * shapePara(num4, num5); } int main() { printf("SUM = %d\n", sum(1, 2)); printf("SUM2(2倍的SUM) = %d\n", sum2(2, sum, 1, 2)); /* 函数指针的建立,以便回调使用 int (*callback_sum)(int, int) = sum;(可省略,写成上面形式) printf("SUM2(2倍的SUM) = %d\n", sum2(2, callback_sum, 1, 2)); (功能相同) 其次上面只用函数名sum,是作为函数指针,以便减少代码量。 */ return 0; } /* 此外多提一嘴,以上代码采用顺序编写,所以无需进行事先的函数声明; 否则,要将main函数后面的函数统统进行事先声明,不然会报错的; */笨鸟先废
273***2295@qq.com