c语言学习第20课-回调函数与qsort函数

简介: c语言学习第20课-回调函数与qsort函数

学习目标:

提示:掌握回调函数,qsort函数

学习内容:

  1. 指向函数的函数指针
  2. 回调函数
  3. qsort函数

关于指针函数

先了解一下指针函数与函数指针的区别

指针函数,落脚点在函数,故它是一个函数,函数的返回值有很多,整型值,字符型值等,当然也可以是指针型.指针函数其返回值为指针。声明形式为:

ret *func(args,...)

其中,func表示一个函数,ages是形参列表(复杂函数一般形参较多),而ret *就是函数func的返回值,是一个指针。

例如

int *p(int x,int y);

a与括号里的结合是函数名,调用他以后,得到一个int *类型的指针,x,y是形参。

因为我们知道int *p是定义一个整形指针变量,int* p是一个表示(int*)的变量。故指针函数就是

类型+*函数(函数参数)。

这里提及一下,主要说函数指针。

函数指针

声明为

ret (*p)(args,...)

函数指针的落脚点在指针,故他表示的是一个指针,可以说这个指针用来表示函数的地址形式,该指针指向一个函数,所以它是指向函数的函数指针。其中 ret为为返回值,*p为指针(指向一个函数),args为形参列表。

我们一般这样定义函数指针 类型+(指针)+函数参数

int (*p)(int ,int);

我们写一个加法函数和减法函数,在定义函数指针用来存放函数。

int Add(int x,int y)
{
  return x + y;
}
int sub(int x, int y)
{
  return x - y;
}
int main()
{
  int (*pf)(int, int) = Add;
  int(*pfArr[4])(int, int) = { Add,sub };//pfArr是一个函数指针数组
  int* (*ppfArr[4])(int, int) = {Add, sub};//ppfArr是一个指向函数指针数组的指针变量
  return 0;
}

其中也有函数指针数组及其指针的表示方法。

回调函数

在函数传参中,传入函数指针类型的参数时,该函数就是一个回调函数。继续用求和函数展示:

//回调函数
void Calc(int(*p)(int, int))//假设传进来的是加减乘除函数 调用的函数即为回调函数
{
  int x = 0;
  int y = 0;
  int ret = 0;
  printf("请输入两个数");
  scanf("%d %d",&x,&y);
  ret = p(x,y);//p为函数指针
  printf("%d", ret);
}

qsort函数

qsort函数是一个库函数,它的功能是用来排序的,其中是以升序的方式排序,本质为快速排序。

因为冒泡排序中传入的参数类型只能为整形,不能排序字符,结构体等,故qsort函数被作用来排序各种类型的数据。

//冒泡排序
void bubbil_sort(int arr[], int sz)
{
  //两两比较,升序
  int i = 0;
  for (i = 0; i < sz - 1; i++)
  {
    for (int j = 0; j < i; j++)
    {
      if (arr[j]>arr[j + 1])
      {
        int temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
}
//算法实现的数据类型单一,例如上述函数只能有整形函数

qsort函数其定义

void qsort(void*base,//排序的第一个元素
  size_t num,//待排元素个数
  size_t size,//每个元素大小,单位字节
  int (*cmp)(const void *p1 ,const void *p2))//指向一个函数,这个函数可以比较两个元素大小

qsort函数优点:  直接用就可排序,,,,可以排序任意类型的数据。

其中需要注意的是,因为是任意数据类型,故void* 表示无具体类型地址 ,只是一个表示可以是任意类型,并没有确切类型。   并且关于void *p=&a;"void *类型不能*p(简引用操作)",此时可用强制类型转换数据类型为某一类型。

在上述定义中,int(*cmp)(const void*p1,const void *p2)是指向一个函数,这个函数由你自己来构造,这个函数用来比较这两个元素大小且这两个元素因为是任意类型,排序哪一种确定的类型数据,你所构造的函数就是该类型数据。其他类型需重新构造在调用。

如排序一组整型的数据

  int cmp_int(const void*, const void*)  //比较两个整形数据  
{
  return *(int*)p1 - *(int*)p2;//强制类型转化  升序排
}//返回值与0比较
  test1()
  {
  int arr[] = { 9,8,7,6,5,4,3,2,1 };
  int sz = sizeof(arr);
  qsort(arr, sz, sizeof(arr[0], cmp_int);//提供一个比较函数,可比较两个整形函数
  }
  int main()
{
  test1();
  return 0;
}

若数据类型为结构体

//排序结构体
  struct stu
  {
    char name[20];
    int age;
  };
  int cmp_stu_age(const void* p1,const void* p2)//排序年龄
  {
    return ((struct stu*)p1->age) - ((struct stu*)p2->age);
  }
  int cmp_stu_age(const void* p1, const void* p2)//排序名字
  {
    return strcmp(((struct stu*)p1->name) , ((struct stu*)p2->name));
  }
  void test2()
  {
    struct stu a[] = { {"zhangsan",20} ,{"lisi",25}, {"wangwu",50} };
    int sz = sizeof(a) / sizeof(s[0]);
    qsort(a,sz,sizeof(s[0]),cmp_stu_age)
   }

当然因为冒泡排序类型固定,我们可以这样改写使得冒泡排序与qsort函数具有相同的功能。

其中参数就是qsort函数中这样的一个形参。

用void *base表示首元素。size_t  num表示元素个数,size_t  size为字节大小,cmp为一个比较字符大小的函数指针。

//用冒泡排序写快速排序
  void bubble_sort(void *base,size_t num,size_t size,int (*cmp)(const void *p1,const void *p2))
    {
    //确定趟数
    int i = 0;
    size_t size= 0;
    for (i = 0; i < num - 1; i++)
    {
      for (int j = 0; j < num - 1; j++)
      {
        if (cmp((char *)base+j*size,(char *)base+j+1*size) > 0)
        {
          sawp((char*)base + j * size, (char*)base + j + 1 * size, size);  //交换
        }
      }
    }
    }
  void swap(char* p1, char* p2, int size)
  {
    int i = 0;
    for (i = 0; i < size; i ++ )
    {
      char temp =*p1;
      *p1 =*p2;
      *p2 = temp;//交换字符
      p1++;
      p2++;
    }
  }

这里的冒泡排序中,因为数据类型不确定,但无论是整形,还是结构体里的元素,还是字符型,都可以用字节大小来比较,此时强制类型转换为字符型,乘以相对应自己的字节大小,这样每个数据都可表示出来(char *)base+j*size,

相关文章
|
1月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
759 0
|
3月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
262 15
|
8月前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
235 1
一文彻底搞清楚C语言的函数
|
9月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
223 3
|
存储 C语言
C 语言函数完全指南:创建、调用、参数传递、返回值解析
函数是一段代码块,只有在被调用时才会运行。 您可以将数据(称为参数)传递给函数。 函数用于执行某些操作,它们对于重用代码很重要:定义一次代码,并多次使用。
378 3
|
C语言
C语言函数返回值详解
本文详细解析了C语言中函数返回值的概念与应用。从函数的基本定义入手,深入探讨了不同类型返回值的作用及意义,并提供了实用的编程示例,帮助读者更好地理解和使用函数返回值。通过本文,你将掌握如何有效利用返回值优化代码结构与功能实现。
1026 2
|
C语言
C语言---函数---知识点总结(三)------函数的返回值类型
C语言---函数---知识点总结(三)------函数的返回值类型
|
存储 C语言
C语言的函数返回值和指针
C|函数返回值(区分各类值)和指针(区分各类存储空间)的细节
|
存储 C语言
C语言中向函数传递值和从函数返回值的技术解析
C语言中向函数传递值和从函数返回值的技术解析
218 0
|
C语言
在C语言中函数的返回值及其应用示例
在C语言中函数的返回值及其应用示例
271 2