⭐️ 高阶指针 ⭐️回调函数(回调型计算器/冒泡排序/qsort函数)

简介: 前言本文主要讲解回调函数的理解回调实现计算器qsort各种功能的使用冒泡排序各种功能的实现

前言


  • 本文主要讲解
  • 回调函数的理解
  • 回调实现计算器
  • qsort各种功能的使用
  • 冒泡排序各种功能的实现

回调函数

  • 定义

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

如果你把函数的指针(地址)作为参数传递给另一 个函数,

当这个指针被用来调用其所指向的函数时,我们就说这是回调函数

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

  • 示例1:

回调型计算器

#define _CRT_SECURE_NO_WARNINGS
#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;
}
int moveleft(int x, int y)
{
  return x << y;
}
int moveright(int x, int y)
{
  return x >> y;
}
int mici(int x, int y)
{
  if (y >= 2)
    return x * mici(x, y - 1);
  return x;
}
int xor(int x, int y)
{
  return x ^ y;
}
//写出相应功能的函数
void menu()
{
  printf("************************\n");
  printf("***1.add        2.sub***\n");
  printf("***3.mul        4.div***\n");
  printf("*5.moveleft 6.moveright*\n");
  printf("***7.xor       8.mici***\n");
  printf("******** 0.exit ********\n");
  printf("************************\n");
}
void cola(int (*p)(int, int))//回调函数 形参为函数指针,接受函数地址
{
  int x, y;
  printf("请输入两个操作数:\n");
  scanf("%d %d", &x, &y);
  int ret = p(x, y);//利用函数指针,即函数地址来调用相应的函数
  printf("得到结果为:%d\n", ret);
}
int main()//计算器逻辑模拟
{
  int intput = 0;
  do {
    menu();
    printf("请选择:\n");
    scanf("%d", &intput);
    switch (intput)
    {
    case 0:
      printf("退出成功!\n");
      break;
    case 1:
      cola(add);//传入的函数降维成函数地址
      break;
    case 2:
      cola(sub);
      break;
    case 3:
      cola(mul);
      break;
    case 4:
      cola(div);
      break;
    case 5:
      cola(moveleft);
      break;
    case 6:
      cola(moveright);
      break;
    case 7:
      cola(xor);
      break;
    case 8:
      cola(mici);
      break;
    default:
      printf("输入错误!\n");
      break;
    }
  } while (intput);
  return 0;
}
  • 示例2:

回调冒泡排序(模拟qsort库函数)

  • 首先演示一下qsort函数的使用

qsort函数原型

void qsort(
    void *base,
    size_t nmemb,
    size_t size,
    int (*compar)(const void *, const void *)
    );
  •   头文件:<stdlib.h>
  •   函数功能:qsort()函数的功能是对数组进行排序,数组有nmemb个元素,每个元素大小为size
  •   参数base : base指向数组的起始地址,通常该位置传入的是一个数组名
  •  参数nmemb :nmemb表示该数组的元素个数
  •   参数size :size表示该数组中每个元素的大小(字节数)
  •   参数(*compar)(const void *, const void *):此为指向比较函数的函数指针
  •   函数返回值:无

compar参数

定义:实现比较功能的函数

注意:两个形参是const void *型(便于接收不同指针类型参数)

内部需将const void *型转换成实际类型(访问元素对应的空间大小,空类型指针无法反问)

int compar(const void *p1, const void *p2)
{
}
  •   如果compar返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的前面
  •   如果compar返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定
  •   如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的后面


方法一

 int compare (const void * a, const void * b)
 {
   if ( *(MyType*)a <  *(MyType*)b ) return -1;
   if ( *(MyType*)a == *(MyType*)b ) return 0;
   if ( *(MyType*)a >  *(MyType*)b ) return 1;
 }

注意:MyType是换成实际数组元素的类型

  • 方法二:

以实际元素是int为例

 int compare (const void * a, const void * b)
 {
     return ( *(int*)a - *(int*)b );
 }

注意:如果变量 a 指向一个较小的负整型数,b指向一个较大的正整型数,(*(int*)a - *(int*)b) 表达式会计算出一个正数,因此,比较int类型元素的大小可以使用大于、小于运算符来比较

代码演示

#include<stdio.h>
#include<stdlib.h>//qasort函数头文件
#include<string.h>//strcmp函数头文件
struct stu//构建结构体,结构体同样是一种类型
{                //注意结构体类型的作用域,放在前面,后面才能使用结构体
  char name[9];
  int age;
};
int cmp_int(const void* e1, const void* e2)//要实现多功能qsort,所以传入的地址类型会有多种形式
{                                          //而void*空指针类型可以来接收不同的类型,便于保持参数一致性,构成回调函数的特点,形参和返回类型一致
  return *(int*)e1 - *(int*)e2;//知道该使用什么类型,就将其先强制转成对应类型(访问空间大小与指针类型有关),再解引用得到空间内容        
}//e1 - e2为升序,e2-e1为降序
int cmp_char(const void* e1, const void* e2)
{
  return *(char*)e1 - *(char*)e2;//字符类型直接比较,比较的是对应的ASCII码值
}
int cmp_double(const void* e1, const void* e2)
{
  return (int)(*(double*)e1 - *(double*)e2);
}
int cmp_stu_name(const void* e1, const void* e2)
{
  return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);//name是字符串,比较需要使用strcmp函数
}//结构体指针->成员 这样访问便捷
int cmp_stu_age(const void* e1, const void* e2)
{
  return ((struct stu*)e1)->age - ((struct stu*)e2)->age;//age为整型,直接比较
}
int main()
{
  char ch[] = { 'e','g','a','f','p','b' };
  int arr1[] = { 6,4,5,9,1,2,4,6,3 };
  double arr2[] = { 5.00,4.00,9.00,3.00,7.00 };
  struct stu s[] = { {"zhangsan",18},{"lisi",20},{"wangwu",22} };
  qsort(ch, sizeof(ch) / sizeof(ch[0]), sizeof(ch[0]), cmp_char);
  for (int i = 0; i < sizeof(ch) / sizeof(ch[0]); i++)
  {
    printf("%c ", ch[i]);
  }printf("\n");
  qsort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), cmp_int);//最后的形参是函数,传入的是函数地址,qsort也相当于是一个回调函数
  for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
  {
    printf("%d ", arr1[i]);
  }printf("\n");
  qsort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), cmp_double);
  for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
  {
    printf("%lf ", arr2[i]);
  }printf("\n");
  qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_name);
  for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
  {
    printf("%s ", s[i].name);
  }printf("\n");
  qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_age);
  for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
  {
    printf("%d ", s[i].age);
  }printf("\n");
                //qsort函数相应比较的功能函数需要自己写
  return 0;
}vv

输出结果:

20210815220728918.png

冒泡排序(bubble_sort)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stu
{
  char name[9] ;
  int age;
};
void sway(char* e1, char* e2,int size)//交换函数 使用char*指针指向一个字节,还需要宽度,才能将元素对应的空间完全交换,实现交换元素
{
  for (int k = 0; k < size; k++)
  {
    char temp = *e1;
    *e1 = *e2;//解引用实现内容交换
    *e2 = temp;
    e1++;//指向下一个字节空间地址
    e2++;
  }
}
void bubble_sort(void* base, int count, int size, int (*cmp)(const void*, const void*))//模拟qsort函数
{
  for (int i = 0; i < count - 1; i++)//趟数
  {
    for (int j = 0; j < count - 1 - i; j++)//一趟中相邻比较对数
    {
      if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)//调用函数 升序
      {
        sway((char*)base + j * size, (char*)base + (j + 1) * size,size);//不符合就交换
      }
    }
  }
}
int cmp_int(const void* e1, const void* e2)
{
  return *(int*)e1 - *(int*)e2;
}
int cmp_char(const void* e1, const void* e2)
{
  return *(char*)e1 - *(char*)e2;
}
int cmp_double(const void* e1, const void* e2)
{
  return (int)(*(double*)e1 - *(double*)e2);
}
int cmp_stu_name(const void* e1, const void* e2)
{
  return strcmp(((struct stu*)e1)->name ,((struct stu*)e2)->name);
}
int cmp_stu_age(const void* e1, const void* e2)
{
  return ((struct stu*)e1)->age-((struct stu*)e2)->age;
}
//实现比较不同类型函数的功能
int main()
{
  char ch[] = {'e','g','a','f','p','b'};
  int arr1[] = { 6,4,5,9,1,2,4,6,3 };
  double arr2[] = { 5.00,4.00,9.00,3.00,7.00 };
  struct stu s[] = { {"zhangsan",18},{"lisi",20},{"wangwu",22} };
  bubble_sort(ch, sizeof(ch) / sizeof(ch[0]), sizeof(ch[0]), cmp_char);
  for (int i = 0; i < sizeof(ch) / sizeof(ch[0]); i++)//打印
  {
    printf("%c ", ch[i]);
  }
  printf("\n");
  bubble_sort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), cmp_int);
  for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
  {
    printf("%d ", arr1[i]);
  }
  printf("\n");
  bubble_sort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), cmp_double);
  for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
  {
    printf("%lf ", arr2[i]);
  }
  printf("\n");
  bubble_sort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_name);
  for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
  {
    printf("%s ", s[i].name);
  }
  printf("\n");
  bubble_sort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_age);
  for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
  {
    printf("%d ", s[i].age);
  }
  printf("\n");
  return 0;
}


相关文章
|
22天前
|
搜索推荐 C语言 C++
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现3
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现
|
3天前
|
存储 C语言
指针数组作为main函数的形参
指针数组作为main函数的形参
12 0
|
1月前
|
安全 C语言 C++
字符指针做函数参数
字符指针做函数参数
9 1
|
1月前
|
安全 C语言
字符指针作函数参数的深入探索
在C语言编程中,字符指针是一个重要的概念,尤其在处理字符串和文本数据时。当我们将字符指针作为函数参数时,可以实现多种灵活和高效的操作。本文将深入探讨字符指针作为函数参数的应用,并通过代码示例加以说明。
14 1
|
1月前
|
存储 Shell C语言
指针数组组main函数的形参
指针数组组main函数的形参
10 0
|
1月前
|
C语言 C++
指针变量作为函数参数
指针变量作为函数参数
8 1
|
1月前
|
存储 Serverless 编译器
怎样定义和使用指向函数的指针变量
怎样定义和使用指向函数的指针变量
8 0
|
1月前
|
C++
用指向指针函数作函数参数
用指向指针函数作函数参数
8 1
|
1月前
|
存储 C语言 C++
什么是函数的指针
什么是函数的指针
8 0
|
1月前
|
存储 C语言
c语言函数指针和指针函数的区别,以及回调函数的使用。
c语言函数指针和指针函数的区别,以及回调函数的使用。
9 0