⭐️ 高阶指针 ⭐️回调函数(回调型计算器/冒泡排序/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;
}


相关文章
|
23天前
|
存储 C语言 C++
如何通过指针作为函数参数来实现函数的返回多个值
在C语言中,可以通过将指针作为函数参数来实现函数返回多个值。调用函数时,传递变量的地址,函数内部通过修改指针所指向的内存来改变原变量的值,从而实现多值返回。
|
23天前
|
存储 搜索推荐 C语言
如何理解指针作为函数参数的输入和输出特性
指针作为函数参数时,可以实现输入和输出的双重功能。通过指针传递变量的地址,函数可以修改外部变量的值,实现输出;同时,指针本身也可以作为输入,传递初始值或状态。这种方式提高了函数的灵活性和效率。
|
1月前
|
C++
指针中的回调函数与qsort的深度理解与模拟
本文详细介绍了回调函数的概念及其在计算器简化中的应用,以及C++标准库函数qsort的原理和使用示例,包括冒泡排序的模拟实现。
17 1
|
1月前
利用指针函数
【10月更文挑战第2天】利用指针函数。
17 1
|
1月前
|
算法 搜索推荐 C语言
【C语言篇】深入理解指针4(模拟实现qsort函数)
【C语言篇】深入理解指针4(模拟实现qsort函数)
23 2
|
5月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
22 0
|
2月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
3月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
|
3月前
|
C语言
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)