• 指针深入了解——函数指针,函数指针数组,指向函数指针数组的指针。


    前言:

    我们上期了解了,数组指针,指针数组,我们知道了,数组也有自己的地址,那么函数有没有自己的地址呢?如果有那又该怎么存起来呢?今天我们就一起来探讨一下。

    一.函数的地址

    先看一段代码吧:

    1. #include
    2. void test()
    3. {
    4. printf("hehe\n");
    5. }
    6. int main()
    7. {
    8. printf("%p\n", test);
    9. printf("%p\n", &test);
    10. return 0;
    11. }

     运行结果:

     输出的都是函数 test()的地址,而且是一样的,所以我们也就是到了,无论是&函数名,还是单独的函数名,都是函数的地址。

    二.函数指针

    我们已经知道了函数怎么获得函数的地址,那么又该怎么存储呢?

    假如我们有一个变量 pfun来存储函数的地址:首先需要存储的是地址,那么地址就需要指针来存储,首先pfun就需要是一个指针,而且指针指向的是一个函数,既然指向的是一个函数,就需要注明函数的返回值和参数例如:

    1. #include
    2. int add(int a,int b)
    3. {
    4. return a + b;
    5. }
    6. int main()
    7. {
    8. int (*pfun)(int, int) = add;
    9. return 0;
    10. }

     如果把pfun去掉就是指针的类型了。

    int (*  )(int, int) = add;

     函数指针调用函数:

    1. #include
    2. int add(int a,int b)
    3. {
    4. return a + b;
    5. }
    6. int main()
    7. {
    8. int (*pfun)(int, int) = add;
    9. int sum = add(3, 5);
    10. int sum1=(* pfun)(3, 5);
    11. int sum2 = pfun(3, 5);
    12. printf("sum=%d\nsum1=%d\nsum2=%d",sum,sum1, sum2);
    13. return 0;
    14. }

     这里我们在对使用函数指针调用函数时,这里的 * 加与不加,都可以,因为函数名本身就也是地址,我们使用函数名调用函数时,就相当于是使用函数的地址在调用函数了,而函数指针存储的就是函数的指针。

    三.两个变态代码:

    1. //代码1
    2. (*(void (*)())0)();
    3. //代码2
    4. void (*signal(int, void(*)(int)))(int);

    这都是什么代码呀,看着就头疼。

    下面来一起分析一下:

    (1)代码一:

     这是不是就清晰了。

    (2)代码二:

     四.函数指针数组

    我们知道了函数指针,那么有函数指针,可不可以有存储函数指针的数组呢,这个答案是肯定的。

    (1)函数指针数组的语法形式

    int (*arrPfun[2])(int, int);

    形式解读:

     (2)函数指针数组的使用

    我们来实现一个建议的计算器,首先实现加减的函数,通过选择数组的下标来选择运算的种类。

    1. #include
    2. int add(int a, int b)
    3. {
    4. return a + b;
    5. }
    6. int sub(int a, int b)
    7. {
    8. return a - b;
    9. }
    10. void mune()
    11. {
    12. printf("**********************************\n");
    13. printf("*********1.加法 2.减法*********\n");
    14. printf("********* 0.exit ********\n");
    15. printf("**********************************\n");
    16. }
    17. int main()
    18. {
    19. int (*arrPfun[3])(int, int) = { 0,add,sub };
    20. int input;
    21. do
    22. {
    23. mune();
    24. printf("请输入操作类型:>");
    25. scanf("%d", &input);
    26. if (input > 0 && input < 3)
    27. {
    28. printf("\n请输入两个操作数:>");
    29. int a = 0, b = 0;
    30. scanf("%d %d", &a, &b);
    31. int ret = arrPfun[input](a, b);
    32. printf("%d \n", ret);
    33. }
    34. else if (input >= 3)
    35. {
    36. printf("输入错误,请重新选择新.\n");
    37. }
    38. } while (input);
    39. return 0;
    40. }

     运行结果:

     五.回调函数

    (1)回调函数定义:

    就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

    (2)库函数qsort的使用

     qsort快速排序库函数,不仅可以排序数组,还可以排序字符串,结构体等。

     代码示例:

    1. #include
    2. #include
    3. Print_arr(int* arr, int sz)
    4. {
    5. int i = 0;
    6. for (i = 0; i < sz; i++)
    7. {
    8. printf("%d ", arr[i]);
    9. }
    10. printf("\n");
    11. }
    12. int com(const void* e1,const void* e2)
    13. {
    14. return (*(int*)e1) - (*(int*)e2);
    15. }
    16. int main()
    17. {
    18. int arr[] = { 54 ,84,32,42,12,20,13,60,26 };
    19. int sz = sizeof(arr) / sizeof(arr[0]);
    20. printf("排序前:");
    21. Print_arr(arr, sz);
    22. qsort(arr, sz, sizeof(arr[0]), com);
    23. printf("排序后:");
    24. Print_arr(arr, sz);
    25. return 0;
    26. }

     (3)超级冒泡排序

     qsort的底层排序方法是快速排序,今天我们用冒泡排序为底层,借助qsort的实现细节,结合回调函数,来实现一下qsort冒泡版,不仅可以排序数据们还可以排序字符串,结构体的超级冒泡排序。

    函数的传参设计,我们还是借鉴qsort的传参模板。

    1. Print_arr(int* arr, int sz)
    2. {
    3. int i = 0;
    4. for (i = 0; i < sz; i++)
    5. {
    6. printf("%d ", arr[i]);
    7. }
    8. printf("\n");
    9. }
    10. int com(void* e1, void* e2)
    11. {
    12. return (*(int*)e1) - (*(int*)e2);
    13. }
    14. swap(char* ch1, char* ch2, size_t sz)
    15. {
    16. int i = 0;
    17. for (i = 0; i < sz; i++)
    18. {
    19. char ch = *(ch1 + i);
    20. *(ch1 + i) = *(ch2 + i);
    21. *(ch2 + i) = ch;
    22. }
    23. }
    24. void qsort_1(void* arr, size_t num, size_t sz, int (*com)(const void*,const void*))
    25. {
    26. int i = 0;
    27. for (i = 0; i < num - 1; i++)
    28. {
    29. int j = 0;
    30. for (j = 0; j < num - 1 - i; j++)
    31. {
    32. if (com((char*)arr + j * sz, (char*)arr + (j + 1) * sz)>0)
    33. {
    34. swap((char*)arr + j * sz, (char*)arr + (j + 1) * sz, sz);
    35. }
    36. }
    37. }
    38. }
    39. int main()
    40. {
    41. int arr[] = { 54 ,84,32,42,12,20,13,60,26 };
    42. int num = sizeof(arr) / sizeof(arr[0]);
    43. printf("排序前:");
    44. Print_arr(arr, num);
    45. qsort_1(arr, num, sizeof(arr[0]), com);
    46. printf("排序后:");
    47. Print_arr(arr, num);
    48. return 0;

    六.函数指针数组

    指向函数指针数组的指针是一个 指针指针指向一个 数组 ,数组的元素都是 函数指针。

    1. void test(const char* str)
    2. {
    3. printf("%s\n", str);
    4. }
    5. int main()
    6. {
    7. //函数指针pfun
    8. void (*pfun)(const char*) = test;
    9. //函数指针的数组pfunArr
    10. void (*pfunArr[5])(const char* str);
    11. pfunArr[0] = test;
    12. //指向函数指针数组pfunArr的指针ppfunArr
    13. void (*(*ppfunArr)[5])(const char*) = &pfunArr;
    14. return 0;
    15. }

     

     最后:

    今天看到了《神话》里面的玉漱公主,太漂亮了,给大家分享一下

     

     

  • 相关阅读:
    【JavaWeb】简易表白墙的设计
    12个微服务架构模式最佳实践
    和孩子斗智斗勇 - 第二回合: 限制微软应用商店
    记一次 腾讯会议 的意外崩溃分析
    C++标注模板库(STL)-deque介绍
    信息的定义与特征,构成世界的三大要素:物质、能量、信息
    【TensorRT】Win10系统python/c++安装tensorrt库
    视频汇聚平台EasyCVR从一分屏切换到四分屏后加载记录显示黑屏该如何解决?
    Linux 下如何调试代码
    TSN新技术,让您的设备网络“更实时、更确定、更安全”
  • 原文地址:https://blog.csdn.net/qq_63943454/article/details/126347389