场景 | 数组指针 | 函数指针 |
---|---|---|
指向内容 | 数据(数组) | 代码(函数) |
取地址差异 | arr ≠ &arr |
Add == &Add |
调用方式 | 需解引用 + 下标 | 直接当函数名用 |
Add
函数为例):int Add(int x, int y) { // 返回int,参数int,int
return x + y; // 实现加法
}
int (*)(int, int)
(返回值 + 参数列表)定义思路:
// 1. 先写一个普通函数(返回int,参数int,int)
int Add(int x, int y) { return x + y; }
// 2. 定义函数指针(抄函数返回值+参数,套括号+*)
int (*pf)(int, int); // ✨ 口诀:返回值 (*指针名)(参数)
// 3. 赋值(函数名=地址,直接抄!)
pf = Add; // 等价于 pf = &Add;(&可省略,函数名天生是地址)
带箭头标注:
int // ← 和Add的返回值一致(都是int)
(*pf) // ← 定义指针pf,*表示这是指针(⚠️括号必加!不然变成返回指针的函数)
(int, int) // ← 抄Add的参数列表(数量/类型必须一模一样)
= Add; // ← 直接赋值函数名,不用写&(函数名=地址,天生一对!)
*pf
的意义:
int *pf(int, int); // ❌ 错误!这是“返回int*的函数”(叫“指针函数”,和函数指针没关系)
int (*pf)(int, int); // ✅ 正确!重点在“指针”,指向一个返回int、参数int,int的函数
pf = &Add; // 取地址(规范写法)
pf = Add; // 直接赋值(更常用,编译器知道函数名就是地址)
pf
已指向Add
):// 方式1:直接当函数名用(推荐,简单到爆炸)
int res1 = pf(3, 5); // 输出8,和Add(3,5)完全一样!
// 方式2:带解引用调用(新手友好,好理解)
int res2 = (*pf)(3, 5); // 输出8,加*只是“仪式感”,编译器会自动处理
// 方式3:千万别这么写!
int res3 = *pf(3, 5); // ❌ 错误!等价于*(pf(3,5)),先调用函数再解引用返回值(返回值是int,解引用会报错)
为什么*pf(3,5)
会错?
()
优先级比*
高,所以先执行pf(3,5)
(调用函数,返回 int)*8
),就像对 “数字 8” 按遥控器,完全没意义!// 1. 定义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 Div(int a, int b) { return a / b; }
// 2. 定义函数指针(指向“带两个int参数、返回int”的函数)
typedef int (*OpFunc)(int, int); // 给函数指针类型起个外号叫OpFunc
// 3. 万能计算函数(通过传入不同函数指针,实现不同运算)
int Calculator(int x, int y, OpFunc op) {
return op(x, y); // 用函数指针调用具体运算函数
}
// 4. 调用:传入不同运算函数
int result1 = Calculator(10, 3, Add); // 调用加法,结果13
int result2 = Calculator(10, 3, Sub); // 调用减法,结果7
int result3 = Calculator(10, 3, Mul); // 调用乘法,结果30
int result4 = Calculator(10, 3, Div); // 调用除法,结果3(整数除法)
Calculator
:“我需要计算,具体用哪个函数你别管,我会给你”op
,把Add
/Sub
等函数 “快递” 给Calculator
Calculator
收到后,直接用op(x,y)
调用,实现 “算法不变,逻辑可变”定义形式 | 本质 | 一句话区别 |
---|---|---|
int (*pf)(); |
函数指针(指针是主体) | “这是一个指针,指向函数” |
int *pf(); |
指针函数(函数是主体) | “这是一个函数,返回指针” |
int Add(int, int);
int (*pf)(double, double) = Add; // ❌ 错误!参数类型要完全一样(int≠double)
int (*pf)(); // 未初始化的函数指针(不知道指向哪里,像没插电的遥控器)
pf(1, 2); // ❌ 危险!可能让程序崩溃(指向乱码地址)
表达式 | 数组名(int arr[10] ) |
函数名(int Add() ) |
---|---|---|
表达式 |
首元素地址 | 函数入口地址 |
&表达式 |
整个数组地址 | 还是函数入口地址(和表达式一样!) |
printf("%d\n", sizeof(pf)); // 输出8(64位系统),因为只存地址,和函数多大没关系
返回值类型 (*指针名)(参数1类型, 参数2类型) = 函数名;
例:int (*pf)(int, int) = Add;
(指向加法函数)
指针名(参数1, 参数2); // 推荐!简单直接,和普通函数调用一样
(*指针名)(参数1, 参数2); // 可选!加*更直观,适合新手理解
返回值类型 通用函数(参数, 函数指针名) {
return 函数指针名(参数); // 用传入的函数指针执行具体逻辑
}
int Max(int, int)
(求两数较大值),并调用它计算7
和5
的最大值Mod
函数(求余数),并测试调用&
,而数组指针必须写&
?(提示:回顾数组名的两个例外)如果觉得有用,欢迎点赞收藏~