• 认识函数指针


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


            目录

    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类型
  • 相关阅读:
    视频压缩技术—H264
    Python 3.10.9 Mac m1 无法安装grpc的解决办法
    【论文笔记】Attention Is All You Need
    如何快速调整SMT贴片编程中的特殊元件角度?
    【.Net实用方法总结】 整理并总结System.IO中TextWriter类及其方法介绍
    uniapp瀑布流:他的数据是纵向渲染,怎么实现动态上拉加载数据?
    EasyExcel处理Mysql百万数据的导入导出案例,秒级效率,拿来即用!
    现代计算方法或可使潜艇狼群战术再现
    关于技术面试思考
    mysql 快速上传数据
  • 原文地址:https://blog.csdn.net/challenglistic/article/details/127398734