深入浅出C语言函数指针:从入门到实战(附完整代码实例)
在C语言的学习中,函数指针是一个核心且进阶的知识点,它既可以让代码更灵活、更具扩展性,也是实现回调函数、动态分发、模块化编程的关键。本文结合百度、必应的高频讲解思路,用通俗的语言+完整可运行的代码,带你彻底掌握函数指针。
一、什么是函数指针?
简单来说:函数指针是指向函数的指针变量。
- 普通指针指向变量的内存地址,函数指针指向函数的代码段内存地址;
- 函数名本身就是函数的入口地址,因此可以直接赋值给函数指针;
- 通过函数指针,我们可以像调用函数一样调用指针,实现动态调用函数。
函数指针的标准定义格式
// 基础格式返回值类型(*指针变量名)(参数类型1,参数类型2,...);示例:
// 定义一个函数指针pFunc,指向【返回int、参数为两个int】的函数int(*pFunc)(int,int);二、基础实战:函数指针的定义、赋值、调用
这是最基础的用法,帮你快速理解核心逻辑。
完整代码
#include<stdio.h>// 定义两个普通函数intadd(inta,intb){returna+b;}intsub(inta,intb){returna-b;}intmain(){// 1. 定义函数指针:指向返回int、参数为两个int的函数int(*pFunc)(int,int);// 2. 赋值:函数名就是地址,直接赋值pFunc=add;// 指针指向add函数// 3. 通过指针调用函数(两种写法等价)printf("3 + 5 = %d\n",pFunc(3,5));// 推荐写法printf("3 + 5 = %d\n",(*pFunc)(3,5));// 传统写法// 4. 重新赋值,指向sub函数pFunc=sub;printf("10 - 4 = %d\n",pFunc(10,4));return0;}运行结果
3 + 5 = 8 3 + 5 = 8 10 - 4 = 6核心要点
- 函数指针必须和指向的函数签名一致(返回值、参数类型/个数完全相同);
(*pFunc)的括号不能省略,否则会变成「返回指针的函数」;- 调用时,
pFunc()和(*pFunc())效果完全一样,推荐简写。
三、进阶用法:函数指针数组(批量管理函数)
当我们需要批量调用多个同类型函数时,函数指针数组是最优解,常用于菜单选择、命令分发等场景。
适用场景
计算器功能选择、游戏指令分发、模块化功能调用。
完整代码
#include<stdio.h>// 定义四个运算函数intadd(inta,intb){returna+b;}intsub(inta,intb){returna-b;}intmul(inta,intb){returna*b;}intdiv(inta,intb){returnb!=0?a/b:0;}intmain(){// 定义函数指针数组:存储4个同类型函数的地址int(*pArr[4])(int,int)={add,sub,mul,div};intx=20,y=5;// 批量调用printf("加法:%d\n",pArr[0](x,y));printf("减法:%d\n",pArr[1](x,y));printf("乘法:%d\n",pArr[2](x,y));printf("除法:%d\n",pArr[3](x,y));return0;}运行结果
加法:25 减法:15 乘法:100 除法:4四、高级实战:函数指针作为函数参数(回调函数)
这是函数指针最常用、最重要的用法——回调函数:把一个函数作为参数传给另一个函数,在合适的时机被调用。
适用场景
排序函数、事件处理、异步操作、遍历数据。
完整代码:通用遍历+回调处理
#include<stdio.h>// 回调函数指针:定义参数类型// 作用:让printArray可以调用不同的打印逻辑typedefvoid(*Callback)(int);// 通用遍历函数:接收数组、长度、回调函数voidprintArray(intarr[],intlen,Callback func){for(inti=0;i<len;i++){func(arr[i]);// 调用回调函数处理每个元素}printf("\n");}// 自定义回调函数1:普通打印voidshowNum(intnum){printf("%d ",num);}// 自定义回调函数2:打印平方voidshowSquare(intnum){printf("%d ",num*num);}intmain(){intarr[]={1,2,3,4,5};intlen=sizeof(arr)/sizeof(arr[0]);printf("原数组:");printArray(arr,len,showNum);// 传入普通打印函数printf("平方值:");printArray(arr,len,showSquare);// 传入平方打印函数return0;}运行结果
原数组:1 2 3 4 5 平方值:1 4 9 16 25核心优势
- 代码解耦:
printArray只负责遍历,不关心具体处理逻辑; - 高度灵活:传入不同回调函数,实现不同功能。
五、简化代码:typedef 重定义函数指针
复杂的函数指针定义可读性差,用typedef可以简化写法,这是企业开发的标准用法。
示例
// 原始写法int(*pFunc)(int,int);// typedef 重定义(推荐)typedefint(*CalcFunc)(int,int);// 直接使用别名定义指针CalcFunc p=add;六、函数指针的常见误区
- 括号不能丢
- 正确:
int (*p)(int)→ 函数指针 - 错误:
int *p(int)→ 返回int*的函数声明
- 正确:
- 函数签名必须匹配
返回值、参数个数、参数类型有一个不同,都不能赋值。 - 无需手动分配/释放内存
函数指针指向代码段地址,不需要malloc/free。
总结
- 函数指针 = 指向函数的指针,核心用途:动态调用函数、实现回调、批量管理函数;
- 基础用法:定义→赋值→调用;
- 进阶用法:函数指针数组(批量调用)、函数指针做参数(回调函数);
- 简化写法:用
typedef重定义函数指针,提升代码可读性。
以上代码均可直接复制编译运行,覆盖了函数指针的高频考点+实战场景,吃透这些,足以应对C语言开发、面试中的绝大多数函数指针问题。
