Я пытаюсь сортировать массив структур, увеличивая одно поле (двойной номер), но кажется, что 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;
}
Я не согласен с вашей заменой. 'sizeof * lev' является агностиком к точкам типа lev и устойчив к изменениям в типе. Жесткое кодирование типа приведет к серьезному поломке (сравнимому с тем, что испытывает OP), если тип когда-либо изменяется, и компилятор не может автоматически диагностировать его для вас. –
@R. С помощью структуры вы получаете дополнительный бонус, сразу видя, сколько кода вы просто сломали (по какой области) с помощью ошибок компилятора. И строка find/replace не очень сложна в эти дни. Читаемость> Lazyness – this
Нет, вы этого не делаете. С struct вы не получаете никакой ошибки вообще и ужасного UB во время выполнения. С версией OP (с фиксированным порядком), как я рекомендую, код автоматически работает. –