qsort 函数是C语言提供的库排序函数,除了解决传统的int数组排序以外,还可以对字符串、结构体等进行排序。这里qsort函数也体现了之前说过的回调函数的机制
在库中长这么个样子:
void qsort ( void * base,
size_t num,
size_t size,
int ( * comparator ) ( const void *, const void * ) );
先简单了解一波qsort函数
1)qsort函数包含在 stdlib.h中。
2) 函数参数,对照上述结构来看:
void *base
表示待排序序列的地址。void * 类型的指针变量意味着可以针对 int、char、struct 等各种类型序列。
size_t num
表示待排序列中关键字的个数。常用sizeof(a)/sizeof(a[0])的形式确定。
size_t size
表示待排序列中关键字的大小,单位为字节。 常用sizeof(a[0])确定。
int ( * comparator ) ( const void *, const void * )
表示 函数指针,该函数指针指向一个返回值为int 参数为两个指针常量的的函数
而这两个指针常量就是待比较的两个关键字。
------------------------------------------分割线-------------------------------------------------------
就使用来说最关键的是要自写一个“比较函数”作为第四个参数传入qsort函数。其中函数对应上述qsort中的形参,返回值必须是int 参数必须是两个指向关键字的指针
而函数返回值需要满足以下特性:
》当前一个关键字比后一个关键字小的时候 return 值 <0;
》当前一个关键字与后一个关键字相等的时候 return 值=0;
》当前一个关键字比后一个关键字大的时候 return 值>0;
注意点:void * 指针有两个典型的特性:
1)可以指向任何类型的变量。
2)void *类型的的指针不能进行解引用操作,因为无法确定类型就无法确定每个单元的字节数,当然也就不能对该指针变量进行偏移操作。因此对这种类型指针要解引用的时候需要强转类型。
上例子:
1)排序int数组
结果默认按照关键字升序排列。
#include <stdio.h>
#include <stdlib.h>
//自写一个比较int类型序列的比较函数
int int_cmp(const void* p1,const void* p2)
{
//比较函数返回值要满足上述要求,这里直接返回两个关键字的差值即可
//但是如果直接写: return *p1-*p2; 这个写法是错误的无法通过编译,因为p1,p2是void*类型的指针是不可以直接解引用的!这里需要强转一下写成下面的代码:
return *((int *)p1)-*((int*)p2);//若是 return *((int*)p2)- *((int *)p1);则降序
}
int main()
{
//声明i用于控制遍历数组
int i=0;
//初始化int数组
int Arr[]={5,6,7,4,3,1}
//定义整型变量方便管理数组的元素个数
int sz=sizeof(Arr)/sizeof(Arr[0]);
qsort(Arr,sz,sizeof(Arr[0],int_cmp);//待排序列地址、待排关键字个数、关键字大小、比较函数地址 四个参数都准备完毕,已经可以开始排序。
for(i=0;i<sz;++i)
{
printf("%d",Arr[i]);
}
}
运行结果:
2)排序字符串数组
还是首先要处理好比较函数,与int_cmp函数相类似,定义char_cmp比较函数:
#include <stdio.h>
#include <stdlib.h> //因为要用到qsort 函数
#include <string.h> //因为要用到strcmp函数
int char_cmp(const void* p1, const void* p2)
{
return strcmp(*(char**)p1,*(char**)p2);
//先用(char**)强转,再用*解引用一层
}
int main()
{
int i=0;
//定义字符串指针数组
char* p[]={"xiongda","gtqiang","xionger"};
int sz=sizeof(p)/sizeof(p[0]);
qsort(p,sz,sizeof[p[0]),char_cmp);
for(i=0;i<sz;++i)
{
printf("%s\n",*p[i]);
}
return 0;
}
字符串是不可以直接相加减的,需要利用一个库函数strcmp函数,它在string.h中
strcmp函数返回值刚好满足比较函数返回值要求,因此直接返回strcmp函数即可
运行结果:
可知是按照字符串依次对比字符,字符默认按照降序排列。
3)排序结构体
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//定义结构体,取别名STU
typedef struct stu
{
int age;
char* name;
} STU;
int cmp_by_name(const void* p1,const void* p2)
{
return strcmp((STU*)p1->name,(STU*)p2->name);
}
int main()
{
int i=0;// 用于遍历结构体数组
//定义结构体数组
STU stu[]={{20,"zhangmazi"},{40,"tangshiye"},{32,"huangsilang"}};
int sz=sizeof(stu)/sizeof(stu[0]);
qsort(stu,sz,sizeof(stu[0]),cmp_by_name);
for(i=0;i<sz;++i)
{
printf("%d %s\n",stu[i].age,stu[i].name);
}
return 0;
}
运行结果:
结果按照名字排名。
当然你还可以设计一个按照年龄排名的比较函数,这里不多说。