qsort中的compare函数是如何工作的?

qsort中的compare函数是如何工作的?,c,quicksort,C,Quicksort,我在网上找到了这个示例代码,它解释了qsort函数的工作原理。我无法理解compare函数返回的是什么 #include "stdlib.h" int values[] = { 88, 56, 100, 2, 25 }; int cmpfunc (const void * a, const void * b) //what is it returning? { return ( *(int*)a - *(int*)b ); //What is a and b? } int main

我在网上找到了这个示例代码,它解释了
qsort
函数的工作原理。我无法理解compare函数返回的是什么

#include "stdlib.h"

int values[] = { 88, 56, 100, 2, 25 };

int cmpfunc (const void * a, const void * b) //what is it returning?
{
   return ( *(int*)a - *(int*)b ); //What is a and b?
}


int main(int argc, _TCHAR* argv[])
{

   int n;

   printf("Before sorting the list is: \n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }

   qsort(values, 5, sizeof(int), cmpfunc);

   printf("\nAfter sorting the list is: \n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }
    return 0;
}
#包括“stdlib.h”
int值[]={88,56,100,2,25};
int cmpfunc(const void*a,const void*b)//它返回什么?
{
return(*(int*)a-*(int*)b);//什么是a和b?
}
int main(int argc,_TCHAR*argv[]
{
int n;
printf(“排序前列表为:\n”);
对于(n=0;n<5;n++){
printf(“%d”,值[n]);
}
qsort(值,5,sizeof(int),cmpfunc);
printf(“\n排序后列表为:\n”);
对于(n=0;n<5;n++){
printf(“%d”,值[n]);
}
返回0;
}

a
b
作为整数进行比较-它们必须作为
void*
传递,但在最终被延迟之前,必须转换为
int*
。至于返回值,它将是正、负或零,所有这些都将在排序函数中考虑。

每当排序算法需要找出两个元素中哪一个应该放在另一个之前时,它将调用比较函数并向这两个元素传递指针。由于您正在对
int
值进行排序,指针实际上是指向
int
的指针,但签名必须采用
void*
,以便可以与任何数据类型一起使用。因此,为了获得实际的元素值,
a
必须转换为
int*
,然后取消引用-因此,
*(int*)a
。如果将
a
放在
b
之前,则函数必须返回负值;如果将
b
放在
a
之前,则函数必须返回正值;如果将哪个放在第一位无关紧要(这通常是元素相等时的情况),则函数必须返回零。在这种特殊情况下,由于我们使用的是数字,只要从
a
的值中减去
b
的值就足够了,如果我们想先得到最大的数字

cmp
函数返回​如果第一个参数小于第二个参数,则为负整数值, 如果第一个参数大于第二个参数,则为正整数值;如果两个参数相等,则为零


该函数使用
void
指针,因此
qsort
函数可用于任何数据类型。但是,在
cmp
函数中,必须显式将指针强制转换为实际数据类型。
a
b
的内容在
qsort
的文档中有明确说明:这些指针指向必须比较的数组元素

本例中的比较函数知道数组元素的类型为
int
。因此,它将
void*
指针强制转换为
int*
类型,并通过从第一个值中减去第二个值来执行指向的
int
值的三态比较

它对您的值集正常工作,但在一般情况下,使用减法进行三态比较是一种糟糕的编程实践,因为它容易溢出。此外,示例代码中的函数不必要地丢弃了指向值的常量

更好的选择是

int cmpfunc(const void *a, const void *b)
{
   const int *A = a, *B = b;
   return (*A > *B) - (*A < *B);
}
int-cmpfunc(常数无效*a,常数无效*b)
{
常数int*A=A,*B=B;
返回(*A>*B)-(*A<*B);
}

qsort将给出它需要与cmpfunc进行比较的每一对,并使用它的返回值查看哪个更大,然后对数组进行相应排序

基本上,如果compare函数返回正结果,这意味着第一个参数大于第二个参数。类似地,如果它返回负数,则第二个参数更大

int cmpfunc (const void * a, const void * b) //what is it returning?
{
   return ( *(int*)a - *(int*)b ); //What is a and b?
}
在本例中,我们要对整数进行排序。所以,当我们比较给定数组的两个元素时,我们需要确定哪个元素更大。为了比较它们,一个简单的减法运算就足够了,因为当a较大时结果为正,如果a和b相等,结果为0,如果b较大,结果为负

int cmpfunc (const void * a, const void * b) //what is it returning?
{
   return ( *(int*)a - *(int*)b ); //What is a and b?
}
相当于:

int cmpfunc (const void * a, const void * b) //what is it returning?
{
   // qsort() passes in `void*` types because it can't know the actual types being sorted
   // convert those pointers to pointers to int and deref them to get the actual int values

   int val1 = *(int*)a;
   int val2 = *(int*)b;

   // qsort() expects the comparison function to return:
   // 
   //    a negative result if val1 < val2
   //    0 if val1 == val2
   //    a positive result if val1 > val2

   return ( val1 - val2 ); 
}
int-cmpfunc(const-void*a,const-void*b)//它返回什么?
{
//qsort()传入'void*`类型,因为它不知道要排序的实际类型
//将这些指针转换为指向int的指针,并对它们进行解引用以获得实际的int值
int val1=*(int*)a;
int val2=*(int*)b;
//qsort()希望比较函数返回:
// 
//如果val1val2,则为阳性结果
返回(val1-val2);
}

它们是从数组
值中读取的整数。函数返回
a
-
b
的值,如果
a
较小,则返回
<0
(一个负数),如果它们相等,则返回
0
,如果a较大,则返回
>0
(一个正数)。qsort的比较函数(实际上是一个回调函数)返回的值与strcmp()完全相同即,如果第一个项目小于第二个项目退货-1如果项目匹配退货0如果第一个项目大于第二个项目退货1@user3629249:小心不要测试特定值
-1
1
strcmp()
(或传递给
qsort()
)的比较函数)允许为这些情况返回任何负值或正值。此比较函数不好,请不要使用它。假设您正在排序-150000000和150000000。减法的结果是-3000000000,这在
int
中无法表示,因此行为未定义。更糟糕的是,生成代码的通常行为是将其包装为正数1294967296,这完全破坏了排序。如果要求比较符号不同的大数字,此比较函数将出现整数溢出。在生产代码中应该避免这种情况。(至少)请查看