• 认识函数指针


    函数指针:一个用于存放一个函数地址的指针,可以用于回调函数的实现。


            目录

    1、认识函数地址

    2、认识函数指针

    (1) 函数指针的声明

    (2) 函数指针的指针类型

    (3) 函数指针的使用方法

    (4) 函数指针的应用 —— 回调函数

    3、拓展:函数指针数组


    1、认识函数地址

    假设有一个数组int arr[10],arr 代表首元素的地址,而 &arr 代表整个数组的地址

    假设有一个函数void Add(int x, int y),Add就是函数的地址,&Add也是函数的地址,和数组不一样,这两者是等价的。

    2、认识函数指针

    (1) 函数指针的声明

    函数指针的声明和数组指针的声明比较类似,我们要让一个指针指向一个数组,需要知道所指向数组的大小、数组元素类型。同理,要让一个指针指向一个函数,那就需要知道函数形参(包括形参类型、形参个数) 和 函数返回值

    假设我们要保存下面这个函数的地址

    1. int Add(int x, int y)
    2. {
    3. return x + y;
    4. }

    声明的步骤如下:

    • 先用一个变量去接收函数的地址:ptr = &Add;
    • 因为这个变量是一个指针,所以:*ptr = &Add;
    • 这个指针所指向的函数形参类型是两个int类型:(*ptr)(int , int) = &Add
    • 这个指针指向的函数返回值是int类型:int (*ptr)(int , int) = &Add

    因此,完整的函数声明方式是

    int (*ptr)(int , int) = &Add;

     

    (2) 函数指针的指针类型

    数组如果将数组名和数组大小去掉,剩下的的就是数组元素的类型;

    指针如果将指针名去掉,剩下的就是指针类型;

    因此,函数指针的指针类型为

    int (*)(int , int)

    (3) 函数指针的使用方法

    函数指针保存了一个函数的地址,通过解引用,我们可以找到这个函数,因此调用方式如下:

    1. (*ptr)(2 , 3); //等同于调用Add(2 , 3)
    2. // ptr(2 , 3); —— 这种写法是等价的

    注意:上面的 * 是一个摆设,只是便于初学者知道,函数指针解引用可以找到对应的函数,但是实际上不解引用也是可以的,即便是多几个 * 也是一样的。

    (4) 函数指针的应用 —— 回调函数

    =================== 提出问题 ===================

    下面是qsort函数的声明,qsort函数用于给一组数据排序,这组数据可以是任意类型。

    那么问题来了,既然是排序,必然要比较两个数据的大小,如果传入的是自定义类型,该怎么比较大小呢?

    ================ 分析问题 ================

    qsort函数的第三个参数需要传入一个函数指针, 这个参数其实就是在告诉qsort函数,如果我传入一个结构体类型,我是希望通过结构体大小比较,还是通过结构体中的某个成员比较。

    我们可以实际调用试试。假设我们要给一个结构体数组排序,排序方式是通过结构体中的 name 成员来比较大小。

    1. struct Person
    2. {
    3. char name[20];
    4. int age;
    5. };
    6. int main() {
    7. struct Person arr[3] = { { "张三",15 },{ "李四",30 },{ "王五",10 } };
    8. return 0;
    9. }

    第三个参数已经明确了函数的返回值和形参类型,返回值为int,形参2个,都是const void* 类型,实际声明和调用如下:

    1. struct Person
    2. {
    3. char name[20];
    4. int age;
    5. };
    6. int my_compare(const void* e1, const void* e2)
    7. {
    8. return strcmp(((Person*)e1)->name, ((Person*)e2)->name);
    9. }
    10. int main() {
    11. struct Person arr[3] = { { "张三",15 },{ "李四",30 },{ "王五",10 } };
    12. qsort(arr, 3, sizeof(Person), my_compare);
    13. for (size_t i = 0; i < 3; i++)
    14. {
    15. printf("%s\n", arr[i].name);
    16. }
    17. return 0;
    18. }

    打印结果如下:

     

    3、拓展:函数指针数组

    函数指针数组其实就是一个保存函数指针的数组,去掉数组名和数组大小就是函数指针的类型。假设我们要保存的函数指针类型为

    int (*)(int,int)

     我们加上数组名和数组大小,即ptrArr[10],那么函数指针数组为

    int (*ptrArr[10])(int,int)

    上述函数指针数组 ptrArr 保存的函数必须满足:

    • 返回值是int
    • 形参有两个,均为int类型
  • 相关阅读:
    【Filament】材质系统
    [附源码]JAVA毕业设计个人交友网站(系统+LW)
    携职教育:最新人力资源管理师报考条件政策解析
    CAP理论和BASE思想
    CI2454 2.4g无线MCU芯片应用
    Vue-Router学习记录
    驱动制造业产业升级新思路的领域知识网络,什么来头?
    Linux文件管理命令
    结构体内存对齐规则
    ChatGLM3-6B:新一代开源双语对话语言模型,流畅对话与低部署门槛再升级
  • 原文地址:https://blog.csdn.net/challenglistic/article/details/127398734