qsort函数的作用是将所有数据排序,那么它和普通的冒泡排序或者选择排序有什么区别呢?它不仅仅可以排序数组中的数字,还可以排序结构体。当然升序和降序它都支持,不过输入参数的顺序会有所不同,下面我们来详细讲解一下这个函数。
首先,我们先看一下库函数中它的使用方法:
可以看出qsort的返回值有三种情况:如果p1的值小于p2,那么返回<0;如果p1的值大于p2;那么返回>0;如果p1的值等于p2,那么返回=0。由此可见,如果我们想排序成升序的话,就按照p1,p2的顺序传值,如果我们想排序成降序的话,就按照相反的顺序传值。
下面我们了解一下qsort函数的表现形式:
void qsort(void*base,size_t num,size_t width,int(*cmp)(const void*e1,constvoid*e2));
1.第一个参数void*base指的是待排序数据的起始位置,也就是说如果我们要将数组排序的话,这个就是数组首元素的地址。
2.第二个参数size_t num指的是数组元素的个数,也就是传过去的数组中一共有几个元素。
3.第三个参数size_t width指的是一个元素的字节大小,也就是你传过去的是什么类型的数组,char型就是一个字节,int就是4个字节等。
4.第四个参数int (*cmp)(const void*e1,const void*e2)是一个函数指针,返回类型是int,参数是void*,待比较的两个元素地址,也就是要我们自己定义。那么这个函数就是需要使用者根据实际情况自行定义的比较函数。
排序升序数字
现在我们排序一个简单的数组来实现qsort函数:
#include<stdio.h>
#include<stdlib.h>
void test(){int arr[]={9,8,7,6,5,4,3,2,1};int size=sizeof(arr)/sizeof(arr[0]);qsort(arr,size,sizeof(arr[0]),cmp_int);print(arr,size);
}
int cmp_int(const void*e1,const void*e2){if(*(int*)e1>*(int*)e2)return 1;else if(*(int*)e1==*(int*)e2)return 0;else ifreturn -1;
}
或者,cmp_int函数也可以简化为以下形式:
void cmp_int(const void*e1,const void*e2){return (*(int*)e1-*(int*)e2);
}
排序结构体
升序
struct stu{char name[20];int age;double score;
};
void test(){struct stu arr[3]={{"sandy",20,55.5},{"lily",30,88.0},{"cindy",50,90.0}};int size=sizeof(arr)/sizeof(arr[0]);qsort(arr,size,sizeof(arr[0]);
}
int cmp_stu_by_age(const void*e1,const void*e2){return (((struct stu*)e1)->age-((struct stu*)e2->age);
}
int cmp_stu_by_name(const void*e1,const void*e2){return strcmp(((struct stu*)e1)->name,((struct stu*)e2)->name);
}
这个代码中首先按照学生的年龄排序,年龄是一个整型,所以只要返回大于或小于等于即可,而之后排序的名字是字符串,字符串的排序比较必须用strcmp函数,所以返回类型通过调用strcmp函数来实现。
降序
了解了升序的代码,下面我们来实现降序的代码:
int cmp_stu_by_age(const void*e1,const void*e2){return (((struct stu*)e2->age-((struct stu*)e2->age);
}
int cmp_stu_by_name(const void*e1,const void*e2){return strcmp(((struct stu*)e2)->name,((struct stu*)e1)->name);
}