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

コードには多くのエラーがあります。

1. compareByErr

関数の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;
}

2. compareByErr

別の問題があります。それは、を暗黙的にに変換することdoubleですint。これらの「エラー」はすべて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

3番目の引数は、配列の各要素のsizeof(perr)サイズであり、ポインターのサイズ(4バイト)だけではありません。その行を次のように変更します。

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

実際に要素サイズを取得します。

idx不要のようです。ここで使用できnumnodeます。

于 2012-09-06T09:20:29.617 に答える
2

比較関数は、構造体へのポインターの配列をソートすることを想定していますが、それは行っていません。この問題は他の答えでカバーされています。

彼らが言及しなかったことは、あなたがsizeofその種類に間違ったものを使用しているということです。配列は構造体の配列であるため、メンバーのサイズが構造体のサイズであることをqsortに通知する必要があります。sizeof perrに変更sizeof *perr

また、floatを比較する前にintに変換すると、すべてゼロであるため、すべてが等しくなります。

于 2012-09-06T09:24:29.847 に答える
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値を生成しますが、他の2つの場合は0または1を生成する比較に依存します。

于 2012-09-06T09:20:45.420 に答える