我尝试对下面的结构进行排序,给出了对错误率进行排序的意图,同时保留了sid和did的信息。虽然没有编译错误,但我在运行时遇到了一个seg错误。我想知道出了什么问题......
#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);
}
答案 0 :(得分:2)
代码中有很多错误。
a
函数的b
和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;
}
还有一个问题是,您隐式将double
转换为int
。由于所有这些“错误”都是0。???,它们都将被截断为0.使整个数组未排序。将其更改为:
double aerr = ((LD*)a)->err;
double berr = ((LD*)b)->err;
return aerr < berr ? -1 : aerr > berr ? 1 : 0;
您正在分配3个 2 节点,但只需要3个节点。将其更改为
perr = (LD*) malloc (numnode * sizeof(LD));
第三个参数是数组中每个元素的大小,而不是sizeof(perr)
,它只是指针的大小(4个字节)。将该行更改为:
qsort(perr, idx, sizeof(*perr), compareByErr);
// ^
实际获取元素大小。
idx
似乎没必要。你可以在这里使用numnode
。
答案 1 :(得分:2)
你的比较函数希望对结构的指针数组进行排序,但你不是这样做的。其他答案涵盖了这个问题。
他们没有提到的是你也使用错误的sizeof
进行排序。由于数组是结构数组,因此必须告诉qsort成员的大小是结构的大小。将sizeof perr
更改为sizeof *perr
此外,在比较它们之前将浮点数转换为整数会导致它们全部相等,因为它们都是零...
答案 2 :(得分: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。