C qsort工作不正常
我不知道我做错了什么,但是下面的代码没有正确地对数组排序C qsort工作不正常,c,qsort,C,Qsort,我不知道我做错了什么,但是下面的代码没有正确地对数组排序 #include <stdio.h> #include <stdlib.h> int compare(const void* a, const void* b) { return (*(int*)a - *(int*)b); } int main() { int x[] = { -919238029, -889150029, -826670576,
#include <stdio.h>
#include <stdlib.h>
int compare(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
int main()
{
int x[] = { -919238029,
-889150029,
-826670576,
-579609061,
-569653113,
-305140505,
-216823425,
-193439331,
-167683147,
-49487019,
-45223520,
271789961,
275570429,
444855014,
559132135,
612312607,
664554739,
677860351,
1005278191,
1031629361,
1089012280,
1115952521,
1521112993,
1530518916,
1907515865,
1931470931,
-1631034645,
-1593702794,
-1465300620,
-1263094822
};
int i;
qsort(x, 30, sizeof(int), compare);
for(i = 0; i < 30; i ++)
printf("%d\n", x[i]);
return 0;
}
我的意思是,问题/必须/在我的比较函数中。有人注意到什么奇怪的事吗?是的,你的“比较”溢出了(
原因:
当从正数减去负数时,结果不一定是正数;如果它不能在数据类型中表示,它将“环绕”另一侧
例子:
如果整数只能保存-8到7(4位),那么将4与-4进行比较时会发生什么情况?那么,你得到8,这是二进制的
1000
,这是-8。所以4小于-4
道德:
不要做减法而不是比较,即使他们告诉你“看这有多酷”在学校!一般情况下,你不能使用减法来比较整数。或者,更准确地说,你可以,但只有在你确信减法不会溢出的情况下。在你的情况下,减法溢出,产生完全没有意义的结果(甚至没有提到当有符号整数减法溢出时,行为是未定义的) 在值
a
和b
之间生成三态C风格比较的常用用法是(a>b)-(a
表达式。它适用于几乎任何可比较类型的数据。在您的情况下,比较函数可能如下所示
int compare(const void* a, const void* b)
{
int va = *(const int*) a;
int vb = *(const int*) b;
return (va > vb) - (va < vb);
}
int比较(常量无效*a,常量无效*b)
{
int va=*(常数int*)a;
int vb=*(常数int*)b;
返回(va>vb)-(va
我用上面的信息给出了一个代码示例。在我的编译器和系统中,我得到的结果与问这个问题的Ram相同。这表明我的整数与Ram的整数类似。我按照Mehrdad的建议修改了代码,使用比较运算符而不是减法。然后我得到了数字泰德表现得很好
#include <stdio.h>
#include <stdlib.h>
int compare(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
int main()
{
int x[] = { -919238029,
-889150029,
-826670576,
-579609061,
-569653113,
-305140505,
-216823425,
-193439331,
-167683147,
-49487019,
-45223520,
271789961,
275570429,
444855014,
559132135,
612312607,
664554739,
677860351,
1005278191,
1031629361,
1089012280,
1115952521,
1521112993,
1530518916,
1907515865,
1931470931,
-1631034645,
-1593702794,
-1465300620,
-1263094822
};
int i;
qsort(x, 30, sizeof(int), compare);
for(i = 0; i < 30; i ++)
printf("%d\n", x[i]);
return 0;
}
代码如下:
#include <stdio.h>
#include <stdlib.h>
int compare(const void* a, const void* b)
{
int
n1 = * (int *) a,
n2 = * (int *) b;
/*
Usine the ternary to express along the lines of
if
elseif
elseif
.
.
.
else
*/
return
n1 > n2 // if
? 1 // then
: n1 == n2 // else if
? 0 // then
: -1 // else
; // end if
}
int main(int argc, char * argv[])
{
int x[] =
{
-919238029, -889150029, -826670576, -579609061, -569653113, -305140505, -216823425, -193439331,
-167683147, -49487019, -45223520, 271789961, 275570429, 444855014, 559132135, 612312607,
664554739, 677860351, 1005278191, 1031629361, 1089012280, 1115952521, 1521112993, 1530518916,
1907515865, 1931470931, -1631034645,-1593702794,-1465300620,-1263094822
};
int
i = 0, // index
imax = sizeof(x)/sizeof(int); // max value for index
FILE * outf = 0;
if ( !(outf = fopen("output.txt", "wt")) )
{
puts("outf == 0 which is an error trying to open \"output.txt\" for writing.\n");
getch();
return;
}
qsort(x, imax, sizeof(int), compare);
for(i = 0; i < imax; i ++)
fprintf(outf, "%d\n", x[i]);
fclose(outf);
return 0;
}
为了补充Mehrad的正确答案,这里有一种自动查找代码中错误的方法,使用: 此警告表示,对于某些输入,
compare
报告x
而不是x
。要进一步调试此问题,请运行
export SORTCHECK_OPTIONS=raise=1
并检查生成的代码转储。不过,不要在另一种语言中尝试使用布尔值@ Mehrdad C++ C++ C++语言。如果你是C++,你错了。这个习语在C++中也很好。在C++中,<代码> > BOOL在减法之前被提升到
vavb?1:0
,如果您有多个排序字段,则易于理解、易于反转和缩放。Mehrdad的评论是准确的——在许多语言中,布尔不是隐式转换成整数的(当然,这是一个C问题,但他确实咧嘴笑了)。@Jim Balter:我发现(va>vb)-(va
明显更简单。一开始它看起来有点新奇,但它的对称性很快使它比两级卷积的?:
运算符(分组不明显)更具可读性。
$ LD_PRELOAD=$HOME/sortcheck-master/bin/libsortcheck.so ./a.out
a.out[38699]: qsort: comparison function is not transitive (comparison function 0x40057d (/home/iuriig/a.out+0x40057d), called from 0x400693 (/home/iuriig/a.out+0x400693), cmdline is "./a.out")
-919238029
-889150029
...
export SORTCHECK_OPTIONS=raise=1