函数指针与回调函数

简介: 函数指针与回调函数

指针作为c语言的重难点,想必也是让很多小伙伴在学习的时候叫苦不迭吧(bushi)。今天主要写一下指针中的函数指针以及使用函数指针回调函数

函数指针的妙用,我们将通过写一个计算器(有菜单,加减乘除)来get。这样的代码对于已经学到指针的我们来说应该是轻车熟路了吧,那就废话不多说直接上代码:

#include<stdio.h>
void meun()
{
  printf("************************************\n");
  printf("********1.add      2.sub   *********\n");
  printf("********3.mul      4.div   *********\n");
  printf("*********0.exit         ************\n");
  printf("************************************\n");
}
int add(int x, int y)
{
  int z = x+y;
  return z;
}
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;
}
int calc(int(*pf)(int, int))//参数为函数指针
{
  int x = 0;
  int y = 0;
  printf("请输入两个操作数:\n");
  scanf("%d%d", &x, &y);
  int ret = pf(x, y);
  printf("%d\n", ret);
}
int main()
{
  int input = 0;
  int x = 0;
  int y = 0;
  int ret = 0;
  do
  {
    meun();//调用菜单,根据input输入的值来确定下一步的函数调用
    printf("请选择:\n");
    scanf("%d", &input);
    switch(input)
    {
    case 1:
      printf("请输入两个操作数—>\n");
      scanf("%d%d", &x, &y);
       ret=add(x, y);
      printf("%d\n", ret);
      break;
    case 2:
      printf("请输入两个操作数—>\n");
      scanf("%d%d", &x, &y);
       ret=sub(x, y);
      printf("%d\n", ret);
      break;
    case 3:
      printf("请输入两个操作数—>\n");
      scanf("%d%d", &x, &y);
      ret=mul(x, y);
      printf("%d\n", ret);
      break;
    case 4:
      printf("请输入两个操作数—>\n");
      scanf("%d%d", &x, &y);
       ret=div(x, y);
      printf("%d\n", ret);
      break;
    case 0:
      printf("退出计算器\n");
      break;
    default:
      break;
    }
  } while (input);
  return 0;
}

这个时候我们就发现在每一个case后面都有相同代码,这样大量重复出现的代码使我们的代码太过冗余了,有没有什么解决办法呢?对于重复出现的代码我们通常将其封装成函数来让代码更简洁,但是封装函数的办法在这好像行不通,因为每一个case后面调用的函数都不相同,那怎么办呢?

ok,这个时候就体现函数指针的妙用了(当然也是可以使用函数指针数组的)。我们单独封装一个calc函数(参数为函数指针的函数)并把add,sub,mul,div这些函数作为参数传给calc函数。先上代码:

#include<stdio.h>
void meun()
{
  printf("************************************\n");
  printf("********1.add      2.sub   *********\n");
  printf("********3.mul      4.div   *********\n");
  printf("*********0.exit         ************\n");
  printf("************************************\n");
}
int add(int x, int y)
{
  int z = x+y;
  return z;
}
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;
}
int calc(int(*pf)(int, int))//参数为函数指针
{
  int x = 0;
  int y = 0;
  printf("请输入两个操作数:\n");
  scanf("%d%d", &x, &y);
  int ret = pf(x, y);
  printf("%d\n", ret);
}
int main()
{
  int input = 0;
  int x = 0;
  int y = 0;
  int ret = 0;
  do
  {
    meun();//调用菜单,根据input输入的值来确定下一步的函数调用
    printf("请选择:\n");
    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:
      break;
    }
  } while (input);
  return 0;
}

这样代码是不是少了些,看起来更加简洁,如果使用函数指针数组来实现会更加简洁,此方法放在文末,因为顺着这个代码应该引入回调函数的概念。

这样通过函数指针调用的函数就是一个回调函数,它并不是由本身直接调用,而是在calc函数执行到适合的位置时,由calc函数调用。回调函数不但能使代码更简洁,也能使部分函数实现更加强大的功能,比如冒泡排序,以前我们写的冒泡排序只能排序整形数组,但引入回调函数后,可以改良它使它能实现任何数据类型的排序。

#include<stdio.h>
struct Stu
{
  char name[20];
  int age;
};
void Swap(char*buf1, char* buf2, int width)
{
  int i = 0;
  for (i = 0; i < width; i++)
  {
    char tmp = *buf1;
    *buf1 = *buf2;
    *buf2 = tmp;
    buf1++;
    buf2++;
  }
}
void bubble_sort(void*base, int sz, int width, int(*cmp)(const void*e1, const void*e2))
{
  int i = 0;
  //趟数
  for (i = 0; i < sz - 1; i++)
  {
    int flag = 1;//假设数组是排好序
    //一趟冒泡排序的过程
    int j = 0;
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (cmp((char*)base+j*width, (char*)base+(j+1)*width)>0)
      {
        //交换
        Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
        flag = 0;
      }
    }
    if (flag == 1)
    {
      break;
    }
  }
}
int cmp_stu_by_name(const void* e1, const void* e2)
{
  //strcmp --> >0 ==0 <0
  return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int main()
{
  struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} };
  int sz = sizeof(s) / sizeof(s[0]);
  bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}

只要改动bubble_sort的最后一个参数就可以实现排序不同类型的目标。这就是函数指针与回调函数的强大。当然肯定还有更多妙用之处等待我们去挖掘。

                 

 

写在后面:

用函数指针数组实现计算器:

int main()
{
  int input = 0;
  int x = 0;
  int y = 0;
  int ret = 0;
  //转移表
  int (*pf[5])(int, int) = { 0,add,sub,mul,div };//有了这个函数指针数组就可以直接通过数组下标来调用函数
  do 
  {
    meun();
    printf("请选择\n");
    scanf("%d", &input);
    if (input == 0)
      printf("退出计算器\n");
    else if (input >= 1 && input <= 4)
    {
      //通过input访问数组来调用函数
      printf("请输入两个操作数\n");
      scanf("%d%d", &x, &y);
      ret = pf[input](x, y);//pf是数组名
      printf("%d\n", ret);
    }
    else
    {
      printf("输入错误\n");
    }
  } while (input);
return 0;
}

我好想在文末说两句骚话啊,奈何文化太差,只能等我下次想到再说了。

相关文章
|
6月前
|
Unix
网络编程之 信号捕捉器(函数指针与回调函数)(2)
sigaction()函数 前面我们讲到的内容已经足以用来防止僵尸进程生成的代码。之所以博主还要介绍sigaction()函数是因为它类似于signal()函数,而且完全可以代替后者,也更稳定(主要是书上介绍到了
66 1
|
6月前
|
Linux
网络编程之 信号捕捉器(函数指针与回调函数)(1)
接着我们的信号说下去 之前博主给大家分享到了信号的概念和初步介绍signal函数的形式后就没有继续往下介绍了,实在是因为时间不够,那个时候博主还要上课,现在博主放假了就好好给大家分享一下如何注册信号捕捉,以及信号捕捉器的妙用。
69 1
|
1月前
|
C++
指针中的回调函数与qsort的深度理解与模拟
本文详细介绍了回调函数的概念及其在计算器简化中的应用,以及C++标准库函数qsort的原理和使用示例,包括冒泡排序的模拟实现。
17 1
|
1月前
魔法指针 之 函数指针 回调函数
魔法指针 之 函数指针 回调函数
13 0
|
6月前
指针(5)---回调函数
指针(5)---回调函数
29 0
|
6月前
|
编译器 C语言
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。(下)
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。
42 0
|
5月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
6月前
|
算法 搜索推荐 C语言
c函数指针与回调函数
c函数指针与回调函数
44 2
|
6月前
|
算法 搜索推荐 程序员
C语言中的函数指针和回调函数
C语言中的函数指针和回调函数
42 2
|
6月前
|
存储 C语言
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。(中)
C语言进阶⑪(指针上)(知识点和对应练习)回调函数模拟实现qsort。
37 0