当前位置:   article > 正文

『C语言初阶』第四章-指针(4)

『C语言初阶』第四章-指针(4)

 1.回调函数是什么?

        回调函数就是一个通过函数指针调用的函数。

        如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。

        回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

        在上一节中我们所写的转移表中,我们虽然采用的是函数数组调用的形式,但是实际上是根据用户的输入来调取不同的函数,而我们今天学习了回调函数后,就可以把函数数组的部分优化掉,只采用一个函数作为接口,然后根据函数指针参数,调取不同的函数,更加的直观,简便。

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. void menu()
  4. {
  5. puts("*********************************");
  6. puts("**********1.add 2.sub********");
  7. puts("*********************************");
  8. puts("**********3.mul 4.div********");
  9. puts("*********************************");
  10. puts("**************0.exit*************");
  11. puts("*********************************");
  12. }
  13. int Add(int x, int y)
  14. {
  15. return x + y;
  16. }
  17. int Sub(int x, int y)
  18. {
  19. return x - y;
  20. }
  21. int Mul(int x, int y)
  22. {
  23. return x * y;
  24. }
  25. int Div(int x, int y)
  26. {
  27. return x / y;
  28. }
  29. //接口函数
  30. void calc(int (*pf)(int, int))
  31. {
  32. printf("输入操作数:");
  33. int x, y;
  34. scanf("%d %d", &x, &y);
  35. int ret = pf(x, y);
  36. printf("%d\n", ret);
  37. }
  38. int main()
  39. {
  40. menu();
  41. int x, y;
  42. int input;
  43. do
  44. {
  45. printf("请选择:");
  46. scanf("%d", &input);
  47. switch (input)
  48. {
  49. case 1:
  50. calc(Add);
  51. break;
  52. case 2:
  53. calc(Sub);
  54. break;
  55. case 3:
  56. calc(Mul);
  57. break;
  58. case 4:
  59. calc(Div);
  60. case 0:
  61. break;
  62. default:
  63. printf("选择错误\n");
  64. break;
  65. }
  66. } while (input);
  67. }

2.qsort()使用举例

        qsort是c语言中stdlib.h库中的一个排序函数,可以根据我们所给的参数,排列大小,底层实现是快速排序,通过下面的参数,我们可以看到void* 说明qsort 函数是适用于所有任意类型的函数

        base: 指向要排序的数组的第一个对象的指针

        num: 数组中排序的元素数量

        size: 数组中每个元素的大小(以字节为单位)

        compar: 指向两个元素的函数指针

         将两个指针作为参数(均转化为const void*)。函数通过返回定义元素的顺序:

        

   2.1使用qsort函数排序整型数据

  1. //这里需要注意参数,最好写成const void* 的形式 适配其他类型
  2. int int_cmp(const void* p1, const void* p2)
  3. {
  4. return (*(int*)p1) - (*(int*)p2);
  5. }
  6. int main()
  7. {
  8. int arr[] = { 1,3,5,4,8,9,12,2,3 };
  9. int i = 0;
  10. size_t sz = sizeof(arr) / sizeof(arr[0]);
  11. qsort(arr, sz, sizeof(arr[0]), int_cmp);
  12. for (int i = 0; i < sz; i++)
  13. {
  14. printf("%d ", arr[i]);
  15. }
  16. printf("\n");
  17. return 0;
  18. }

2.2使用qsort 排序结构数据

  1. struct Stu
  2. {
  3. char name[20];
  4. int age;
  5. };
  6. int cmp_stu_by_age(const void* p1, const void* p2)
  7. {
  8. return (*(struct Stu*)p1).age - (*(struct Stu*)p2).age;
  9. }
  10. int cmp_stu_by_name(const void* p1, const void* p2)
  11. {
  12. return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
  13. }
  14. void test2()
  15. {
  16. struct Stu s[] = { {"zhangsan",20},{"lisi",30},{"wangwu",15} };
  17. int sz = sizeof(s) / sizeof(s[0]);
  18. qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
  19. for (int i = 0; i < sz; i++)
  20. {
  21. printf("%s\t", s[i].name);
  22. printf("%d\n", s[i].age);
  23. }
  24. }
  25. void test1()
  26. {
  27. struct Stu s[] = { {"zhangsan",20},{"lisi",30},{"wangwu",15} };
  28. int sz = sizeof(s) / sizeof(s[0]);
  29. qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
  30. for (int i = 0; i < sz; i++)
  31. {
  32. printf("%s\t", s[i].name);
  33. printf("%d\n", s[i].age);
  34. }
  35. }
  36. int main()
  37. {
  38. test1(); //按照年龄排序
  39. printf("\n");
  40. test2(); //按照名字排序
  41. return 0;
  42. }

需要注意 strcmp 是string.h的库函数,专门用来比较两个字符串的大小的,且比较的是字典序,也就是依次比较ASCII码,返回值正好与我们构建的函数返回值规则一致。

3. qsort函数的模拟实现

        使用回调函数,模拟实现qsort(采用冒泡的方式)

        基本核心:

  1. void qsort(
  2. void* base,//base 指向了要排序的数组的第一个元素
  3. size_t num, //base指向的数组中的元素个数(待排序的数组的元素的个数)
  4. size_t size,//base指向的数组中元素的大小(单位是字节)
  5. int (*compar)(const void* p1, const void* p2)//函数指针 - 指针指向的函数是用来比较数组中的2个元素的
  6. )
  7. {
  8. if (compar(x, y) > 0)
  9. {
  10. //交换
  11. }
  12. }

 实现代码:

        注意其中的字节交换,以及排序时对于元素的变更,都是怎么具体实现的

  1. void swap(void* p1, void* p2,size_t size)
  2. {
  3. //由于不知道类型,所以需要根据参数类型,一个一个字节交换字节里的值来达到元素交换的效果
  4. for (int i = 0; i < size; i++)
  5. {
  6. char temp = *((char*)p1+i);
  7. *((char*)p1+i) = *((char*)p2+i);
  8. *((char*)p2 + i) = temp;
  9. }
  10. }
  11. int int_cmp(const void * p1, const void* p2)
  12. {
  13. return (*(int*)p1 - *(int*)p2);
  14. }
  15. //size_t 是字节类型 是无符号整型数据
  16. void bubble(void* base, int count, size_t size, int (*cmp)(const void*, const void*))
  17. {
  18. int i, j;
  19. i = j = 0;
  20. for (i = 0; i < count-1; i++)
  21. {
  22. for (j = 0; j < count - i - 1; j++)
  23. {
  24. //因为我们不知道传入的数组是什么类型的
  25. // 所以就需要转成char* 然后移动 j*size来移动指针来达到选其他数组元素的目的
  26. if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0) // 大于0 说明 前者大于后者
  27. {
  28. swap((char*)base + j * size, (char*)base + (j + 1) * size,size);
  29. }
  30. }
  31. }
  32. }
  33. int main()
  34. {
  35. int arr[] = { 1,3,5,4,8,9,12,2,3 };
  36. int i = 0;
  37. int sz = sizeof arr / sizeof arr[0];
  38. bubble(arr,sz , sizeof(int), int_cmp);
  39. for (int i = 0; i < sz; i++)
  40. {
  41. printf("%d ", arr[i]);
  42. }
  43. printf("\n");
  44. return 0;
  45. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/154286
推荐阅读
相关标签
  

闽ICP备14008679号