一、函数指针
函数指针是个普通的指针,但是写法略不同于一般的指针,
二、如何定义
函数在结构体外定义,例如:
// 原函数
int add(int a, int b) {return a + b;}
定义函数指针,例如:
// 指向原函数的函数指针
int (*p)(int x, int y);
可以看到,关键字:
1. 返回值类型必须相同
2. 指针变量名要用()括起来
3. 除形参名外,参数列表必须相同
赋值,将指针指向函数(不要忘了这一步)
// 直接将函数名赋值给指针
// 函数名就是一个地址
p = add;
// 可以加取地址&符
p = &add;
三、如何使用
下面三种用法是等价的:
// 直接用:指针名(实参列表)
int a = p(2, 3);
// 用定义时的写法
int b = (*p)(2, 3);
// 不用指针,这里作对照组
int c = add(2, 3);
四、结构体
结构体实现了用户自定义数据类型,解决了基本数据类型不够用的问题
成员可以是普通的数据类型(整型、浮点型、指针、数组等),也支持结构体的嵌套
在定义结构体时不能赋值,因为结构体在没使用时是没有占内存空间,没空间用来赋值。但是在定义后有初值,为0、null或false等
例如:
typedef struct Demo {
int x;
int y;
}; // 不要忘记分号
五、结构体联合函数指针
既然结构体成员可以普通指针,那么函数指针也可以作为成员
同上节的代码:
typedef struct Demo {
int x;
int (*p)(int x, int y);
}; // 不要忘记分号
在使用时,同其他成员一样赋值
// 在某函数中
// 1. 结构体的静态赋值:定义时顺便赋值
struct Demo demo = {1, add};
// 2. 结构体的动态复制
struct Demo demo; // 此时有默认值为0和null
demo.a = 1;
demo.p = add; // 等号右边有两种写法,参考1.1赋值
// 如果定义为结构体指针,访问成员时则用“->”符号
六、重要应用
面向对象编程思想
面向对象是一种思想,有封装、继承、多态三个特点。高度抽象和封装,可以让应用开发者可以忽略实现的具体细节,专注于业务逻辑;代码的可重用性,让应用开发者少复制很多代码。它们不只是某些编程语言的专门特性。
C语言本身是不支持类class的,但是不乏优秀的开发者将面向对象的思想应用在C语言上面,实现起来虽然不方便,但是正是有这些思想,让开发者从C语言获得启发,开发出了更加易用和健壮的高级语言。
回调函数
函数指针变量可以作为某个函数的参数来使用的,回调函数本质就是一个通过函数指针调用的函数。
七、完整示例
/* 输出:
* 5
* 5
* 5
*/
#include <stdio.h>
// 原函数
int add(int a, int b) { return a + b; }
int main() {
// 定义函数指针
int (*p)(int x, int y);
// 两种赋值方法
// p = add;
p = &add;
// 三种调用函数的方法
printf("%d\n", p(2, 3));
printf("%d\n", (*p)(2, 3));
printf("%d\n", add(2, 3));
return 0;
}