8.函数指针-vs-指针函数.md 3.7 KB

函数指针 vs 指针函数

判别规则(核心,唯一要记的)

  • 无括号 int *fp(int) → fp 是函数(指针函数,返回 int*)
  • 有括号 int (*fp)(int) → fp 是指针(函数指针,指向 int(int) 类型的函数)

一句话:"返回指针的,是函数;指向函数的,是指针。" 函数指针的最大用途 = 回调。

抽象描述(一句话本质)

函数指针 = 把函数当"值"存起来的指针,可像变量一样传递、存储、调用(回调的根基);指针函数 = 普通函数,只是返回值是指针。函数名(函数指示符)用作值时自动退化成函数指针。

正反例(建立直觉)

  • 正例1int add(int a,int b){return a+b;}int (*fp)(int,int) = add; int r = fp(3,4); r = 7((*fp)(3,4) 写法等价)
  • 正例2:回调经典 qsort(arr, n, sizeof(int), cmp); —— qsort 最后一个参数就是函数指针
  • 正例3:嵌入式注册回调 void register_callback(void (*handler)(void));register_callback(my_isr);
  • 反例1int *fp(int) 指针函数——普通函数,fp(5) 返回 int*,与回调无关
  • 反例2:函数名本身 == 函数指针,add&add 都能赋给函数指针,等价

易混对比

int (*fp)(int) int *fp(int)
fp 是什么 指针(指向函数) 函数(返回 int*)
名字 函数指针 指针函数
怎么用 fp(x) 调用指向的函数;作回调参数 调用它拿回指针
记忆 括号护 * → fp 是指针 没括号 → fp 是函数

变体验证(3 题,全过=学会)

  1. char *(*fp)(void)函数指针,指向"无参、返回 char*"的函数
  2. 陷阱题:int (*p)(int) = f; A 编译通过int *p(int) = f; B 报错——B 声明的是"返回 int* 的函数"不是指针变量,函数不能拿来赋值
  3. 回调场景:void on_event(void (*cb)(int)); + void my_cb(int v); → 调用写 on_event(my_cb);(函数名直接当函数指针传,不用加 &

口述要点(面试怎么讲)

  • 结论先行:没括号 = 函数(返回指针);括号护 * = 指针(指向函数)
  • 为什么函数名能直接当函数指针:函数名是"函数指示符",用作值时自动退化成函数指针(add&add 等价)
  • 回调的本质(解耦):框架函数只和"签名"打交道,不依赖具体实现;传入不同的函数就注入不同的行为,一个框架复用任意逻辑(多态)。嵌入式里中断→回调尤其重要:底层模块向上层发通知,却不反向依赖上层 = 低耦合
  • 嵌入式高频场景:中断向量表本身就是函数指针数组、qsort 比较器、状态机转移表、struct 函数指针表(C 版虚函数表,统一接口封装底层差异)
  • 易错点:把"返回指针的函数"当成"函数指针";函数名传参不用加 &

关系网络

相邻概念 和本主题的关系 孤立理解会犯的错
数组指针 vs 指针数组 同款"括号结合"思想:int (*fp)(int) 函数指针 / int (*p)[N] 数组指针 记混两套名字,实际是一套规则
回调 函数指针的最大用途:把行为当参数传,解耦调用者和实现 以为回调就是"套娃调用",没抓住解耦本质
结构体 + 函数指针 C 实现面向对象多态的根基(函数表/接口) 以为 C 里做不了抽象,只能重复代码
中断 中断向量表 = 函数指针数组;ISR 注册 = 回调 以为中断只能靠硬编码,不懂注册机制

学习日期

2026-08-03


每主题一页,复习时只翻本目录。