Domanda

I am trying to sort array of structs by increase of one field (double number) but it seems that qsort() somehow corrupts data in this array (Printing array out after the call shows that fields were filled with some random values). Moreover, if I change comparator to sort array in descendant order qsort doesn't spoils data anymore but neither it sorts an array - after the call everything is the same. This little program demonstrates the problem:

#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;
}
È stato utile?

Soluzione 3

You switched the parameters in qsort, should be:

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

I replaced *lev with struct level as i think it is better for code readability.

Altri suggerimenti

You've mixed up the number-of-elements and size-of-element arguments to qsort. This way round it works:

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

As noted, you should also use fabs in your comparison macro. I really don't think that you need the comparison with a tolerance for sorting, however, because you're not really looking for equality but for an ascending order. I'd just go with == and make that the last branch, because it virtually never occurs.

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

I do not think it is correct comparing method. Absolute values should be compared something like this way:

#define dbl_eq(x, y) (fabs((x) - (y)) < CMP_PREC)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top