C语言:深入理解指针(5)

发布于:2025-05-16 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

一、回调函数

二、qsort 使用举例

三、模拟qsort


一、回调函数

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

举个例子:

int Add(int x, int y)
{
   return x+y;
}

void test(int (*pf)(int, int))
{
   int r = pf(10 ,20);
   printf("%d\n" ,r);
}

int main()
{
   test(Add);
   return 0;
}

简单点说,就是把函数的地址作为一个参数传递给另外一个函数,在其中被调用,那么被调用的函数就称为回调函数

二、qsort 使用举例

qsort 是C语言中提供的一个排序函数,是基于快速排序思想的。

它的原型如下:

void qsort(void* base, size_t num, size_t size, int(*compar)(const void* ,const void*));

void* base //指针,指向被排序数组的第一个元素

size_t num //元素个数

size_t size //元素的大小(单位:字节)

int (*compar)(const void* ,const void*) //函数指针,指向的函数是用来比较被排序数组中的两个元素,根据自己需要,自己编写

下面举个例子:

int compar(const void* p1, const void* p2)
{
   if( *(int*)p1 > *(int*)p2 )
      return 1;
   else if( *(int*)p1 < *(int*)p2)
      return -1;
   else
      return 0;
}

这个自行编写的函数要满足一下要求:

(1)返回类型为整型

(2)在默认升序的情况下,当 p1 > p2时,返回1, p1 == p2 时返回 0 ,p1 < p2 时返回 -1。

(3)如果你想降序,把(2)中的 条件互换就行

(4)具体的比较标准由你自己来定,你可以比较整形,浮点型,字符型或者其他,不过要记得强制类型转换

三、用冒泡排序模拟 qsort 函数

首先,要模拟,我们需要根据 qsort 函数的原型模拟:

void my_bubble( void* base, size_t num ,size_t size, int (*compare)(const void* ,const void*);

然后我们在把原本普通的冒泡函数写出来:

​
void my_bubble( void* base, size_t num ,size_t size, int (*compare)(const void* ,const void*)
{
   for(int i = 0 ;i <sz-1;i++)
   {
      for(int j = 0 ;j <sz-1-i ;j++)
      {
         if(arr[j] > arr[j+1])//判断条件我们需要修改
         {
            //交换过程我们也要修改
            int mid = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = mid;
         }
   }
}

​

为什么要用void*呢?因为我们不知道要排序的数据类型

为什么要专门写一个比较函数呢?因为我们不提前知道比较规则

那如何比较两个元素呢?我们连数据类型都不知道

如图所示,我们知道起始地址,但不知道元素类型,也就不知道一个元素究竟占多少字节,整型一个元素占4个字节,短整型占两个字节,我们该如何准确地找到下一个元素的地址呢?

如图,别忘了我们还有每个元素的大小,那么第 j 个元素的地址就是 arr+j*size ,j 第 +1 个 元素的地址就是 arr + (j +1)*size 。

但是,void*作为无类型指针,是不可以被计算和解引用的,那我们就要对其强制类型转化为 char* 类型。

为什么是 char* 类型呢?因为char的大小为 1 个字节,是最小的单位了,你总不能拿 int 去吧,你用了int ,那char 、short 怎么办呢

所以那个条件应该为:

if(compar((char*)p1 ,(char*)p2) > 0)

那如果满足这个条件了,按照原先冒泡函数思想,我们就应该互换位置了,那怎么互换呢?

互换一般要创建第三个变量,但是,我们不知道元素类型,就不知道第三者变量的类型,怎么办呢?

我们每个字节每个字节互换:

如此往复循环,直到两个元素调换完成,那我们应该循环几次呢?答案是 size 次,因为每个元素就是 size 个字节,每次调换一个字节,需要调换 size 次

void Swap(char* su1, char*su2 ,size_t size)
{
   for(int i = 0; i<sz ;i++)
   {
      char mid = *su1;
      *su1 = *su2;
      *su2 = mid;
      su1++;
      su2++;
   }
}

好了,我们的用冒泡排序模拟qsort就可以出来了:

​void Swap(char* su1, char*su2 ,size_t size)
{
   for(int i = 0; i<sz ;i++)
   {
      char mid = *su1;
      *su1 = *su2;
      *su2 = mid;
      su1++;
      su2++;
   }
}


void my_bubble( void* base, size_t num ,size_t size, int (*compare)(const void* ,const void*)
{
   for(int i = 0 ;i <sz-1;i++)
   {
      for(int j = 0 ;j <sz-1-i ;j++)
      {
         if(compare((char*)p1+j*size , (char*)p2+(j+1)*size) >0)
         {
            swap((char*)p1+j*size , (char*)p2+(j+1)*size) ,size);
         }
   }
}


网站公告

今日签到

点亮在社区的每一天
去签到