2

我尝试对下面的结构进行排序,目的是对其错误率进行排序,同时保留 sid 和 did 的信息。虽然没有编译错误,但我在运行时遇到了段错误。我想知道哪里出了问题......

#include <stdio.h>
#include <stdlib.h>

struct linkdata {
    int sid;
    int did;
    double err;
};
typedef struct linkdata LD;
typedef int (*qsort_func_t)(const void *, const void *);

static int compareByErr (const void * a, const void * b)
{
    fprintf(stderr, "aerr=%.3f, berr=%.3f\n", (*(LD**)a)->err, (*(LD**)b)->err);
    int aerr = (*(LD**)a)->err;
    int berr = (*(LD**)b)->err;

    return aerr - berr;
}

int main() {

    int idx;
    int numnode;
    struct linkdata* perr;
    qsort_func_t qsort_func = compareByErr;

    numnode = 3;
    perr = (LD*) malloc (numnode*numnode*sizeof(LD));

    perr[0].sid = 0; perr[0].did = 1; perr[0].err = 0.642; 
    perr[1].sid = 0; perr[1].did = 2; perr[1].err = 0.236; 
    perr[2].sid = 0; perr[2].did = 3; perr[2].err = 0.946;
    idx = 3;

    qsort(perr, idx, sizeof(perr), compareByErr);

    int i;
    for (i=0; i<idx; i++){
       fprintf(stderr,"err[%d][%d] = %.3f\n", perr[i].sid, perr[i].did, perr[i].err);            
    }

    free(perr); 
}
4

3 回答 3

2

您的比较函数期望对指向结构的指针数组进行排序,但您没有这样做。其他答案涵盖了这个问题。

他们没有提到的是你也在使用错误sizeof的排序。由于数组是结构体数组,你必须告诉 qsort 一个成员的大小就是一个结构体的大小。更改sizeof perrsizeof *perr

此外,在比较它们之前将浮点数转换为整数会导致它们都相等,因为它们都为零......

于 2012-09-06T09:24:29.847 回答
2

代码中有很多错误。

1. compareByErr

函数的ab参数compareByErr是 的对象LD*,而不是LD**。你做了一个不必要的取消引用。尝试将该功能更改为:

static int compareByErr (const void * a, const void * b)
{
    fprintf(stderr, "aerr=%.3f, berr=%.3f\n", ((LD*)a)->err, ((LD*)b)->err);
    int aerr = ((LD*)a)->err;
    int berr = ((LD*)b)->err;

    return aerr - berr;
}

2. compareByErr

还有另一个问题,您隐式地将 转换doubleint. 由于所有这些“错误”都是 0.???,它们都将被截断为 0。使整个数组未排序。将其更改为:

    double aerr = ((LD*)a)->err;
    double berr = ((LD*)b)->err;

    return aerr < berr ? -1 : aerr > berr ? 1 : 0;

3.malloc

您正在分配 3 个2个节点,但只需要 3 个。将其更改为

perr = (LD*) malloc (numnode * sizeof(LD));

4. qsort

第三个参数是数组中每个元素的大小,sizeof(perr)而不仅仅是指针的大小(4 个字节)。将该行更改为:

qsort(perr, idx, sizeof(*perr), compareByErr);
//                      ^

实际获得元素大小。

idx似乎没有必要。你可以在numnode这里使用。

于 2012-09-06T09:20:29.617 回答
1

您错误地处理了比较器回调的参数。

这个:

fprintf(stderr, "aerr=%.3f, berr=%.3f\n", (*(LD**)a)->err, (*(LD**)b)->err);

应该:

{
  const LD *lda = a, *ldb = b;

  fprintf(stderr, "aerr=%.3f, berr=%.3f\n", lda->err, ldb->err);
  /* ... */
}

当然,您不必引入适当类型的新变量,但它会使后续代码变得容易得多。我总是这样做。

此外,这:

int aerr = (*(LD**)a)->err;
int berr = (*(LD**)b)->err;

return aerr - berr;

非常简洁,但它可以隐藏有点可怕的整数溢出问题。我会推荐:

return (a->err < b->err) ? -1 : a->err > b->err;

这使用显式文字来生成-1值,同时依赖于为其他两种情况生成 0 或 1 的比较。

于 2012-09-06T09:20:45.420 回答