2013-11-22 54 views
-1

我想通过增加一个字段(双数)来对结构数组进行排序,但似乎qsort()以某种方式破坏了此数组中的数据调用显示字段填充了一些随机值)。此外,如果我将比较器更改为按后代顺序排序数组,qsort不会损坏数据,但它不会对数组进行排序 - 在调用之后,所有内容都是相同的。 这个小程序演示了此问题:qsort()比较数组的结构:非常奇怪的行为

#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; 
} 

回答

0

您切换快速排序中的参数,应该是:

qsort(lev, size , sizeof(struct level) , levels_compar); 

我换成*levstruct level因为我认为这是对代码的可读性更好。

+1

我不同意你的替换。 'sizeof * lev'与'lev'指向的类型是不可知的,并且在类型的变化中是强健的。如果类型发生变化并且编译器无法为您自动诊断,那么对该类型进行硬编码将导致严重的破坏(与OP所经历的相当)。 –

+0

@R。通过使用struct,您可以通过编译器错误立即查看刚刚破解的代码(在什么范围内),从而获得额外的好处。并且字符串查找/替换在这些日子里不是很难。可读性>懒惰 – this

+1

不,你不知道。使用struct,您在运行时不会出错,并且可怕的UB。随着OP的版本(固定订单)就像我推荐的那样,代码会自动工作。 –

0
#define dbl_eq(x, y) ((x) - (y) < CMP_PREC) 

我不认为这是正确的比较方法。绝对值应该比较像这样:

#define dbl_eq(x, y) (fabs((x) - (y)) < CMP_PREC) 
+0

是的,当然。当我准备问题代码时,只是犯了这个错误。我现在要更改问题中的代码,但问题仍然存在。 –

2

你混了和元素大小的论点中的元素数到qsort。这种方式它的工作原理:

qsort(lev, size, sizeof(*lev), levels_compar); 

如上所述,您还应该在您的比较宏中使用fabs。然而,我认为你不需要与排序的容忍度进行比较,因为你并不是在寻找平等,而是在按升序排列。我只想跟==一起去做最后一个分支,因为它几乎从不发生。

+0

在检查相等计算结果时,您不应该用'=='比较浮点数。在这种情况下,我们并不是在检查平等性,而是为了序列。当数值应该在数组中切换时,具有容差的检查实际上可能会使数值略微不符合,因为一个数值小于另一个数值,但在容差范围内,但不会被切换,因为两个数值被认为是相等的。一般来说,比较花车与宽容是好的建议,但我认为这是错误的。 (此外,这种建议往往会导致容易被空气抽出) –

+0

你是对的,平等可能被完全排除在外。 – this