如何解决qsort 比较函数能否始终返回非零值?
qsort
数组上 bsearch
和 int
的升序排序回调函数可能如下所示:
int ascending(const void *o1,const void *o2) {
int a = *(const int *)o1;
int b = *(const int *)o2;
return a < b ? -1 : 1;
}
然而这个函数似乎违反了 C 标准中对 compar
函数的约束:
7.22.5.2 qsort
函数
概要
#include <stdlib.h>
void qsort(void *base,size_t nmemb,size_t size,int (*compar)(const void *,const void *));
说明qsort
函数对 nmemb
对象数组进行排序,其中的初始元素由 base
指向。每个对象的大小由 size
指定。
数组的内容根据compar
指向的比较函数按升序排序,调用该函数时带有两个指向被比较对象的参数。如果第一个参数被认为分别小于、等于或大于第二个参数,则该函数应返回一个小于、等于或大于零的整数。
如果两个元素比较相等,则它们在结果排序数组中的顺序是未指定的。
这个比较函数是否正常或者是否会导致未定义的行为?
解决方法
C 2018 7.22.5 4 说:
当相同的对象(由 size 字节组成,不管它们在数组中的当前位置)被多次传递给比较函数时,结果应该彼此一致。也就是说,对于 qsort
,它们将定义数组的总排序,对于 bsearch
,相同的对象将始终以相同的方式与键进行比较。
A total order 要求 a = a。 (要从维基百科页面的定义中看出这一点:Connexity 说,对于任何 a 和 b,a ≤ b 或 b ≤ a。用 a 代替 b 得到 a ≤ a 或 a ≤ a。所以 a ≤ a。那么反对称的条件满足:我们有 a ≤ a 和 a ≤ a,所以 a = a。)
,至少将这样的函数与 bsearch
一起使用会导致未定义的行为。
这是一个演示程序。
#include <stdio.h>
#include <stdlib.h>
int ascending(const void *o1,const void *o2) {
int a = *(const int *)o1;
int b = *(const int *)o2;
return a < b ? -1 : 1;
}
int ascending1(const void *o1,const void *o2) {
int a = *(const int *)o1;
int b = *(const int *)o2;
return ( b < a ) - ( a < b );
}
int main(void)
{
int a[] = { 2,2,1,0 };
const size_t N = sizeof( a ) / sizeof( *a );
qsort( a,N,sizeof( int ),ascending );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ",a[i] );
}
putchar( '\n' );
int key = 1;
int *p = bsearch( &key,a,ascending );
if ( p ) printf("*p = %d,p - a = %zu\n",*p,( size_t )( p - a ) );
else puts( "Oops!" );
p = bsearch( &key,ascending1 );
if ( p ) printf("*p = %d,( size_t )( p - a ) );
else puts( "Oops!" );
return 0;
}
程序输出为
0 0 1 1 2 2
Oops!
*p = 1,p - a = 3
qsort
能否工作取决于其内部实现。
但在任何情况下,您都有未定义的行为,因为比较函数不满足要求。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。