2013-11-22 56 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