C qsort()比较结构数组:非常奇怪的行为
我试图通过增加一个字段(双倍数字)对结构数组进行排序,但qsort()似乎以某种方式破坏了该数组中的数据(在调用显示字段中填充了一些随机值后打印出数组)。此外,如果我将comparator更改为按后代顺序对数组进行排序,qsort不会再破坏数据,但也不会对数组进行排序—在调用之后,一切都是一样的。 这个小程序演示了这个问题:C qsort()比较结构数组:非常奇怪的行为,c,arrays,struct,qsort,C,Arrays,Struct,Qsort,我试图通过增加一个字段(双倍数字)对结构数组进行排序,但qsort()似乎以某种方式破坏了该数组中的数据(在调用显示字段中填充了一些随机值后打印出数组)。此外,如果我将comparator更改为按后代顺序对数组进行排序,qsort不会再破坏数据,但也不会对数组进行排序—在调用之后,一切都是一样的。 这个小程序演示了这个问题: #include <stdio.h> #include <stdlib.h> #include <math.h> #include &l
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
/* Macro for comparing floats. */
#define CMP_PREC 0.000001
#define dbl_eq(x, y) (fabs((x) - (y)) < CMP_PREC)
/* Structure for testing. */
struct level {
double alt;
double volume;
double area;
};
/* Create array of levels with random alts.
* (Other fields are unimportant for this demo). */
struct level *create_random_arr(size_t size) {
size_t i;
struct level *lev = NULL;
lev = calloc(sizeof(*lev), size);
srand(time(NULL));
for (i = 0; i < size; i++) {
lev[i].alt = (double) rand() / 1000.0;
lev[i].volume = lev[i].area = 0.0;
}
return lev;
}
/* Prints array in format:
* [index]: alt=[alt], volume=[volume], area=[area]\n */
void print_levels(struct level *lev, int lev_cnt) {
int i;
for (i = 0; i < lev_cnt; i++) {
printf("%d: alt=%g, volume=%g, area=%g\n",
i, lev[i].alt, lev[i].volume, lev[i].area);
}
}
/* Comparator for sorting by increasing of alt. */
static int levels_compar(const void *a, const void *b) {
const struct level *al = (const struct level *) a;
const struct level *bl = (const struct level *) b;
if dbl_eq(al->alt, bl->alt) {
return 0;
} else if (al->alt < bl->alt) {
return -1;
} else {
return 1;
}
}
int main(void) {
int size = 10;
struct level *lev = NULL;
lev = create_random_arr(size);
/* Print generated array. */
print_levels(lev, size);
/* Sort array by increase. */
qsort(lev, sizeof(*lev), size, levels_compar);
/* Print result... very surprising, isn't it? */
printf("----------\n");
print_levels(lev, size);
free(lev);
return 0;
}
#包括
#包括
#包括
#包括
/*用于比较浮动的宏*/
#定义CMP_PREC 0.000001
#定义dbl_eq(x,y)(晶圆厂((x)-(y))alt,bl->alt){
返回0;
}否则如果(al->altalt){
返回-1;
}否则{
返回1;
}
}
内部主(空){
int size=10;
结构级别*lev=NULL;
lev=创建随机数组(大小);
/*打印生成的数组*/
打印水平(水平、大小);
/*按递增对数组进行排序*/
qsort(lev,sizeof(*lev),大小,级别\u比较);
/*打印结果…非常令人惊讶,不是吗*/
printf(“------------\n”);
打印水平(水平、大小);
免费(lev);
返回0;
}
#定义dbl_等式(x,y)((x)-(y)
我认为这不是正确的比较方法。绝对值应按如下方式进行比较:
#define dbl_eq(x, y) (fabs((x) - (y)) < CMP_PREC)
定义dbl_eq(x,y)(晶圆厂((x)-(y))
您已经将元素的数量和元素参数的大小混合到qsort
。它的工作原理如下:
qsort(lev, size, sizeof(*lev), levels_compar);
如上所述,您还应该在比较宏中使用fabs
。我真的不认为你需要排序的容忍度比较,但是,因为你不是真的在寻找平等,而是一个升序。我只想使用=
并将其作为最后一个分支,因为它实际上从未发生过。您在qsort中切换的参数应该是:
qsort(lev, size , sizeof(struct level) , levels_compar);
我将*lev
替换为struct-level
,因为我认为它更利于代码的可读性。当然可以。我在准备问题代码时犯了这个错误。我现在将更改问题中的代码,但问题仍然存在。在检查计算结果是否相等时,不应将浮点值与=
进行比较。在本例中,我们不是检查相等性,而是检查序列。当数组中的值应该被切换时,带有公差的检查实际上会使值稍微偏离顺序,因为一个值比另一个值小,但在公差范围内,但由于两个值被认为相等,所以不会被切换。一般来说,将浮动与公差进行比较是一个很好的建议,但我认为这是一个误导。(而且,这个建议往往会导致从空气中抽离公差。)我不同意你的更换sizeof*lev
与lev
所指向的类型无关,并且在类型的更改中具有健壮性。如果类型发生更改,并且编译器无法自动为您诊断,则对类型进行硬编码将导致严重的破坏(与OP所经历的情况相当)。@R.使用struct,您可以通过编译器错误立即看到您刚刚破坏了多少代码(在什么范围内)。现在,字符串查找/替换不是很难。可读性>懒散不,你没有。有了struct,您就不会出现任何错误,而且在运行时也不会出现错误。使用我推荐的OP版本(订单固定),代码会自动运行。@R。。如果代码正确,当然会出现错误。同样,懒惰也会带来运行时问题。如果将lev
的类型从struct-level*
更改为struct-level\u-ex*
,您的代码仍会编译得非常好,没有任何警告或错误,但在运行时会严重崩溃(通过调用未定义的行为)。
qsort(lev, size , sizeof(struct level) , levels_compar);