【C进阶】回调函数(指针进阶2,详解,小白必看)(中)

简介: 【C进阶】回调函数(指针进阶2,详解,小白必看)(中)

6.2函数指针数组实现计算器

//函数指针数组实现计算器
int Add(int x, int y)
{
  return x + y;
}
int Sub(int x, int y)
{
  return x - y;
}
int Mul(int x, int y)
{
  return x * y;
}
int Div(int x, int y)
{
  return x / y;
}
void menu()
{
  printf("*************************\n");
  printf("***  1.Add     2.Sub   **\n");
  printf("***  3.Mul     4.Div   **\n");
  printf("***  0.Exit            **\n");
  printf("*************************\n");
}
int main() 
{
  int input = 0;//选择菜单的功能
  int x = 0;
  int y = 0;
  int ret = 0;//用于接收值
    //转移表 - 函数指针的数组
  int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
               //   0    1   2   3    4
  //NULL的作用是为了占用0下标,然后让函数指针数组的元素下标对应上菜单的功能
  do {
    //菜单
    menu();
    //进行选择
    printf("请选择:>");
    scanf("%d", &input);
    //用函数指针数组代替switch
    if (input == 0)
    {
      printf("退出计算器\n");
      return 0;
    }
    else if (input >= 1 && input <= 4)
    {
      printf("请输入两个操作数:>");
      scanf("%d %d",&x,&y);
      ret = (***pfArr[input])(x, y);//其实比函数指针的用法就多了一个[input]
       //跟函数指针一样,调用函数的时候 * 是没有任何意义的
      printf("%d\n",ret);
    }
    else
    {
      printf("选择错误\n");
    }
  } while (input);
  return 0;
}


6ef33d2e4f8846af8a27f752f89274f2.png

函数指针数组是一个数组,其中的元素是函数指针。每个函数指针指向一个特定的函数,可以通过函数指针调用相应的函数。 函数指针数组可以用来解决代码冗余的问题,可以方便地遍历、调用不同的函数,从而简化代码的结构和逻辑,提高代码的可维护性和可扩展性。

函数指针数组的用途:转移表


7. 指向函数指针数组的指针(仅作了解即可)


//指向函数指针数组的指针
int Add(int a, int b)
{
  return a + b;
}
int Sub(int a, int b)
{
  return a - b;
}
int main()
{   //函数指针
  int(*pf)(int, int) = Add;
  //函数指针数组
  int (*pfArr[4])(int, int) = { Add,Sub };
  //指向函数指针数组的指针
   int (*(*ppfArr)[4])(int,int) = &pfArr;
   return 0;
}


如何理解指向函数指针数组的指针:

a777c141ceaa44058969638a6bdd3173.png


8.回调函数


概念

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

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

代码冗余问题:第一版简单的计算器存在的问题

13191edc21374f4f9b9407acbb7e6c97.png

代码冗余问题:第一版简单的计算器存在的问题

这时候就需要用到回调函数解决问题了:


8.1关于回调函数的理解

7bb1141c6fc348d49899cc4d0d97d153.png


8.1.1用回调函数改良简单计算器

#include<stdio.h>
int Add(int x, int y)
{
  return x + y;
}
int Sub(int x, int y)
{
  return x - y;
}
int Mul(int x, int y)
{
  return x * y;
}
int Div(int x, int y)
{
  return x / y;
}
//将冗余重复部分用Calc函数封装(只用了一个函数),通过这个函数里面传入的函数指针调用计算器函数
void Calc(int(*pf)(int, int))//pf函数指针,传过来哪个函数地址就用哪种类型计算
{
  int x = 0;
  int y = 0;
  int ret = 0;
  printf("请输入两个操作数:>");
  scanf("%d %d", &x, &y);
    ret = pf(x, y);
  printf("%d\n", ret);
}


void menu()
{
  printf("*************************\n");
  printf("***  1.Add     2.Sub   **\n");
  printf("***  3.Mul     4.Div   **\n");
  printf("***  0.Exit            **\n");
  printf("*************************\n");
}
int main()
{
  int input = 0;
  int ret = 0;
  do{
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      Calc(Add);
      break;
    case 2:
      Calc(Sub);
      break;
    case 3:
      Calc(Mul);
      break;
    case 4:
      Calc(Div);
      break;
    case 0:
      printf("退出计算器\n");
      break;
    default:
      printf("选择错误\n");
      break;
      }
    } while (input);
  return 0;
}

总结:

回调函数:被作为参数传递的函数,Add、Sub、Mul、Div四个函数就是回调函数,

而Calc函数则是工具人


8.2qsort库函数的使用


8.2.1冒泡排序

回顾一下冒泡排序的过程:

冒泡排序的思想:两两相邻的元素进行比较,假设要排成升序

1e8026c4b8784e279f46fb46f77fe73b.png

怎么去写冒泡排序的代码:

①由元素个数确定趟数

②由趟数确定比较对数        

③两个元素两两交换排成升序

//冒泡排序 
void bubble_sort(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz - 1; i++)//趟数
  {
    int j = 0;
    for (j = 0; j < sz - 1 - i; j++)//比较对数
    {
      if (arr[j] > arr[j + 1])
      {
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
  }
}
void print_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
}
int main()
{
  int arr[] = { 9,8,7,6,5,4,3,2,1,0};
  //排序
  //使用
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sort(arr, sz);
  print_arr(arr, sz);
  return 0;
}

6ce921a0d39d49c8bc321490d5990f3e.png

不足:

但是这个冒泡排序的缺点也很明显,就是只能排整型int

如果遇到浮点型、结构体等类型的数据,就排不了,那么怎么可以解决呢?

这时候就要用到qsort了。


8.2.2qsort的概念

qsort-- quicksort


是一个库函数,是用来排序的库函数使用快速排序的方法

qsort的好处是

1.现成的

2.可以排序任意类型的数据

034e044949bd49aab147fb9cecf24663.png

7c22dbcbdbd5480d8fd5e6cea6633767.png

qsort是可以排序任意类型的数据

1.比较2个整数的大小,> < ==

//qsort函数的使用者提供这个函数
//qsort 默认是升序
int cmp_int(const void* p1, const void* p2)
{
  return *(int*)p1 - *(int*)p2;
    //排成倒序的话,什么都不用动,只需要return *(int*)p2 - *(int*)p1;//调换顺序即可
}
void print_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
}
test1()
{
  int arr[] = { 3,1,5,2,4,9,8,6,5,7 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  //使用qsort来排序整型数组,这里就要提供一个比较函数,这个比较函数能够比较2个整数的大小
  qsort(arr, sz, sizeof(arr[0]), cmp_int);
  print_arr(arr, sz);
}
int main()
{
   test1();
}

894a56b200b84700951ab1315407f61e.png

2.比较2个字符串,strcmp -->回顾字符串知识:http://t.csdn.cn/V7E9a

3.比较2个结构体数据(学生:张三、李四)指定比较的标准

回顾结构体对象访问成员的知识:http://t.csdn.cn/DVEVj

//测试qsort 排序结构体数据
struct Stu {
  char name[20];
  int age;
};
void print_arr1(struct Stu* arr, int sz)//打印年龄
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    //printf("%d ", (*(arr + i)).age);
    //printf("%d ", (arr+i)->age);
    printf("%d ", arr[i].age);
  }
  printf("\n");
}
void print_arr2(struct Stu*arr, int sz)//打印姓名
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%s ", (arr+i)->name);
    //printf("%s ", (*(arr+i)).name);
    //printf("%s ", arr[i].name);
  }
  printf("\n");
}
//按照年龄来比较
int cmp_stu_by_age(const void*p1,const void* p2)
{
  return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
int cmp_stu_by_name(const void* p1, const void* p2)
{
  return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void test2()
{
  struct Stu s[] = { {"zhangsan",30},{"lisi",25},{"wangwu",50} };
  int sz = sizeof(s) / sizeof(s[0]);
  //测试按照年龄来排序
  print_arr1(s, sz);
  qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
  print_arr1(s, sz);
  //测试按照名字来排序
  /*print_arr2(s,  sz);
  qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
  print_arr2(s, sz);*/
}

打印年龄:

e5d479c48d584f4a9240c19eb232a743.png

打印性别:

9832750a1c60423daec46cc0b53efb61.png

相关文章
|
4月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
4月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
4月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
4月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
4月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
42 4
|
4月前
指针进阶(3)
指针进阶(3)
34 1
|
4月前
|
C++
指针进阶(1)
指针进阶(1)
37 1
|
4月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
38 0
|
4月前
|
存储 安全 编译器
C++进阶之路:探索访问限定符、封装与this指针的奥秘(类与对象_上篇)
C++进阶之路:探索访问限定符、封装与this指针的奥秘(类与对象_上篇)
31 0
|
21天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
下一篇
无影云桌面