指针(4)

回调函数

 一个函数的地址当作另一个函数的参数。在另一个函数中用这函数的地址去调用该函数,则该函数为回调函数。

我们只需要了解下它的定义就行。不需要特别关注(毕竟我们是写代码,又不是写它的定义)。

qsort函数

qsort函数的简单介绍 

qsort是一个库函数   其头文件为#include<stdlib.h>   

上方该图为qsort函数的声明。

对于qsort函数   其可以实现将任意类型的数组进行升序或者降序排列。 

当我们使用qsort进行排列时,其qsort函数内部是通过快速排序来实现排列(我们并没学快速排列,其涉及的知识对我来说超纲)

对于其参数四个类型中,唯独最后的函数指针接受其相同类型函数的函数名:所以其接收的函数需要自定义, 要单独拿出来。

该自定义函数是用来进行两个数比较。且降序还是升序由它来控制。当e1所指向的数组中内容大于e2所指向的数组中内容,返回值大于0(小于时,返回值小于0)为升序排列。

相反,当e1内容小于e2时,返回值却大于0。e1内容大于e2时,返回值小于0.则为降序排列。

 

其中不同类型进行排列,该函数就有不同的代码。一般来说比如我们下方的整形格式排列。而其他类型也一样,只要让其能两个数比较出来就行。

  这里再说一点自定义函数类型必须类型为 int(const void*,const void*),因为qsort要求的函数指针类型为int (*)(const void*,const void*),所以类型必须都为这种。

 对于qsort函数的排序不同类型时的不同代码格式,这里我们还展示其他几种特殊的排列。

 结构体排列的自定义函数

结构体进行排列,并不能里面的数据全部同时进行排列,只能选结构体里面的一种数据进行排列

(这个道理显而易见) 

  其中我们用到了结构体操作访问符,之前也介绍过->左边为结构体指针,右边为变量。这里就用到了该操作符。

我们还可以用另外一个操作符。点操作符,左边就为结构体,右边为变量。所以如果用点操作符,则变为    return (int)(*(stu*)e1.weight-*(stu*)e2.weight) .只要返回值正确,用哪个都行。

字符串大小比较

 在说把字符串进行排列时,我们需要提前了解字符串大小比较和字符串长度比较是有区别的

字符串长度比较是直接看谁的字符多。

而字符串大小比较是先拿第一个字符的ascall码值进行比较,谁ascall码值大谁字符串大,如果第一个相等则拿第二个进行比较,依次下去(如果到最后都相同,则相等,也就是两个字符串是一样的) 在下面这篇文章中有更多关于字符串大小比较的细节(总而言之就是比ascall码值)

https://blog.csdn.net/weixin_37962206/article/details/121655942

这篇文章有一个是错误的那就是  abcd依次往后ascall码值不断增大,并不是不断减小

  该篇文章错误为这,搞反了。应该是不断增大。

下面为执行图 ,能证明

字符串大小排列的自定义函数  

strcmp库函数 

了解了以上这些,对于字符串大小进行比较,其实我们有一个库函数可以直接将其进行比较 

那就是strcmp,其头文件为#include<string.h>, 如下是其用途

其参数类型为const char*  ,可以接收char*(隐式转换)和const char*。但如果参数类型为char*,只能接受char *,不能接收const char*(不能隐式转换为char *)

所以我们只需要将整个字符串输入就行,其整个字符串代表首位字符地址类型为char *,可行。之后就通过该库函数内部的代码操作从而比较出来大小。

返回值大于0,则第一个比第二个大。同理小则小,为0则相等

其返回值跟我们自定义函数返回值一样。所以可以完美用于其自定义函数上 

字符串大小排列的自定义函数 

 上述代码没问题,能隐式转换从而变为 const char*,库函数最终会返回出大于0或者小于0或者等于0的值,符合自定义函数的返回值。从而能比较出字符串大小

字符串长度排列的自定义函数

 上方为自定义函数,下方为strlen的声明

 

同理其跟strcmp是一样的道理,char *和const char*都可以接受,从而返回出其长度(类型为size_t,无符号整数)。其这种类型的自定义函数代码如上较为简单,不过多叙述。

关于qsort的自定义函数的更多种类比较代码 

 除以上几种还有更多自定义函数种类比较代码  下面给个链接,里面文章讲述的非常详细。

https://blog.csdn.net/ZDDWLIG/article/details/120209948

模拟qsort函数的实现

由于qsort函数内部是通过快速排序实现的,快速排序的知识点对我们来说超纲了 ,而排序我们只学过冒泡排序,所以模拟实现我们只能通过冒泡排序实现。

其中的代码和qsort内部代码肯定不同。但是虽然不同,我们至少也要了解到底该如何利用这四个参数去实现任意类型(不管其用什么方法),毕竟了解的越多,更能提升我们思维能力。

 

void*能接收任意类型的地址,但其不能用于计算(不能用于跟类型有关的计算),所以需要强制类型转换。

所以我们强制类型转化为char*,之所以用char*,是因为用它计算时是乘1再进行计算,能完美利用参数从而得到所有地址(所有类型的)。用其他的话就有些类型不适用。

而到了交换这来,由于是任意类型都能接收,所以不能把整个类型都交换,因为如果你这次能把int给整个交换,那么它就只能交换int,其他不能整个交换。所以我们这时就想到将一个一个字节进行交换 ,其中任意类型都适用。

 而对于该模拟的qsort函数内部代码,不管任意类型都能实现排序(结构体,字符串等等),且函数内部不变,而只需要变的则是外部的比较的自定义函数。

且我们还可以对该函数进行优化,提高效率,之前冒泡排序有讲到 我们只需要跟普通冒泡排序进行优化一样,跟它一样加几句代码则也可以实现,没有太复杂。

所以这就是qsort函数的模拟实现(用冒泡排序实现跟其本质快速排序实现不一样) ,这模拟实现其实没有太过复杂。我们可以了解下知道它的一些很巧妙的地方,提升下思维。

 目前已知学的库函数

printf  ,scanf  头文件都为 #include <stdio.h>  

strlen  ,strcmp    头文件都为#include <string.h>

qsort  ,rand(在猜数字游戏中出现),  srand(在猜数字游戏中出现)头文件为#include<stdlib.h>  

time   (在猜数字游戏中出现)  头文件为#include<time.h> 

assert库函数所用的头文件#include<assert.h>

这就是目前已学的所有库函数

总结

这就是指针(4) 的内容,内容有点少,其中的重点是qsort函数。  

所以到这就结束了,谢谢大家!

  • 15
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值