Почему этот код, использующий функцию qsort, не работает в C?

Сортировочная часть:

      order = (struct order_s **) calloc(pm->len - q, sizeof(struct order_s*));

      for (i = 0; i < window_pos; ++i) {
              order[i] = (struct order_s *) malloc(sizeof(struct order_s));
              order[i]->pos = i;
              order[i]->good = good[i];
      }
      for (i = window_pos + q; i < pm->len; ++i)
      {
              order[i-q] = (struct order_s *) malloc(sizeof(struct order_s));
              order[i-q]->pos = i;
              order[i-q]->good = good[i];
      }
     qsort(order, pm->len - q, sizeof(struct order_s *), compare);

Функция сравнения:

int compare (const void * a, const void * b)
{
        if ((((const struct order_s *)a)->good - ((const struct order_s *)b)->good) > 0)
                return 1;
        else
                return -1;
}

Структура:

struct order_s {
  int pos;
  double good;
};

Ценности:

(gdb) p pm->len
$35 = 20
(gdb) p window_pos 
$36 = 1
(gdb) p q
$37 = 5

Перед qsort():

(gdb) p *order[0]
$2 = {pos = 0, good = 1.3238653863672125}
(gdb) p *order[1]
$3 = {pos = 6, good = 0.96180564211148134}
(gdb) p *order[2]
$4 = {pos = 7, good = 1.0684181637005736}
(gdb) p *order[3]
$5 = {pos = 8, good = 0.92113662370476379}

После qsort():

(gdb) n
(gdb) p *order[0]
$6 = {pos = 0, good = 1.3238653863672125}
(gdb) p *order[1]
$7 = {pos = 6, good = 0.96180564211148134}
(gdb) p *order[2]
$8 = {pos = 7, good = 1.0684181637005736}
(gdb) p *order[3]
$9 = {pos = 8, good = 0.92113662370476379}

После функции qsort массив структуры не отсортирован правильно и позже выдает ошибку сегмента.


person Hanfei Sun    schedule 30.08.2012    source источник
comment
Так что же делает это? Выглядят ли значения нормальными, если вы сломаетесь внутри compare?   -  person Useless    schedule 30.08.2012
comment
Хороший тест, просто временно вставьте printf в сравнение и посмотрите на сравниваемые значения. Вы можете быть удивлены.   -  person Alan Corey    schedule 29.10.2018


Ответы (1)


Аргументы функции compare() – это указатели на элементы массива. В этом случае элементами массива являются struct order*, что означает, что аргументы compare() равны struct order**, а не struct order*.

Изменить на:

int compare (const void * a, const void * b)
{
    const struct order_s** aa = a;
    const struct order_s** bb = b;

    /* Can two 'order_s' instances never be equal ? */
    if ( (*aa)->good - (*bb)->good) > 0) return 1;
    else  return -1;
}

Из стандартного раздела C99 7.20.5.2 Функция qsort:

Содержимое массива сортируется в порядке возрастания в соответствии с функцией сравнения, на которую указывает compar, которая вызывается с двумя аргументами, указывающими на сравниваемые объекты. Функция должна возвращать целое число меньше, чем, равен или больше нуля, если считается, что первый аргумент соответственно меньше, равен или больше второго.

person hmjd    schedule 30.08.2012
comment
Я думаю, что у compare() все еще есть проблема, поскольку она никогда не возвращает 0. Возможно (хотя и маловероятно), что qsort может вызвать компаратор с указателями на один и тот же объект. Если за это не будет 0, у вас будут плохие времена. - person Adrian McCarthy; 30.08.2012