1. 指针函数:外卖柜的「生存法则」
核心痛点:返回局部变量地址导致崩溃?堆区与栈区傻傻分不清?
生活类比:
-
栈区 ≈ 临时摊位(函数结束即销毁)
-
堆区 ≈ 智能外卖柜(手动申请释放,长期有效)
代码对比:
// 错误!返回栈区地址(临时摊位被拆)
char* bug_demo() {
char buf[32] = "hello";
return buf; // 危险操作!
}
// 正确!返回堆区地址(外卖柜长期存餐)
char* correct_demo() {
char* buf = (char*)malloc(32);
strcpy(buf, "hello");
return buf; // 安全返回,记得用完free!
}
避坑指南:
-
永远不要返回局部变量地址!
-
malloc
后必须检查是否成功(if (buf == NULL)
) -
使用后务必
free()
,否则内存泄漏!
2. 二级指针:遥控指挥「外卖小哥」
场景:在函数内修改外部指针的指向
错误示例:
void create_space(char* p) { // p是外部指针的副本
p = malloc(32); // 修改副本不影响原指针
}
char* q = NULL;
create_space(q); // q仍为NULL,后续操作崩溃!
正确方案(二级指针传递):
void create_space(char** p) { // p是q的遥控器
*p = malloc(32); // 直接操作q的地址
}
char* q = NULL;
create_space(&q); // q成功指向堆区空间
关键点:
-
二级指针相当于“遥控器”,直接操控原指针的地址
-
适用于动态内存分配、链表操作等场景
3. 函数指针:你的「万能遥控器」
核心价值:通过指针调用不同函数,实现代码灵活扩展(如插件系统、回调机制)。
定义与使用:
// 定义函数类型:接受两个int参数,返回int
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main() {
int (*remote)(int, int); // 声明“遥控器”
remote = add; // 绑定加法按钮
printf("%d\n", remote(3, 5)); // 输出8
remote = sub; // 切换减法按钮
printf("%d\n", remote(5, 2)); // 输出3
}
实战应用(函数指针作为参数):
int calculate(int (*op)(int, int), int a, int b) {
return op(a, b); // 通过指针调用不同操作
}
// 调用示例
calculate(add, 10, 5); // 15
calculate(sub, 10, 5); // 5
4. 函数指针数组:遥控器上的「快捷键」
场景:快速切换多个功能(如计算器菜单)
// 定义三个函数
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
// 声明函数指针数组
int (*buttons[3])(int, int) = {add, sub, mul};
// 使用示例
printf("%d\n", buttons[0](5, 3)); // 加法 → 8
printf("%d\n", buttons[2](5, 3)); // 乘法 → 15
终极避坑清单
-
返回栈区地址:局部变量地址在函数结束后失效,必须用
malloc
申请堆空间。 -
内存泄漏:
malloc
后忘记free
,长期运行导致程序崩溃。 -
二级指针误用:想修改外部指针时,需传递指针的地址(
&q
)。 -
函数指针类型不匹配:指针声明必须与函数签名完全一致(参数类型、返回值)。
练习题
-
声明一个指向函数的指针,该函数接受两个
float
参数并返回double
。 -
声明一个包含4个元素的函数指针数组,每个函数无参数且返回
int*
。
(答案在评论区)