在 C 中对结构使用 qsort 时出现分段错误

Segmentation Fault when using qsort on struct in C

我正在尝试编写一个程序来读取包含多个结构的二进制文件并打印该数据的排序版本,但每当我尝试 运行 qsort 时,它都会出现分段错误。我知道是 qsort 导致了分段错误,因为删除它可以让程序顺利 运行。

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>

typedef struct Data_s {
double dest;
float dec;
char colour[9];
short dress;
int experience;
char voyage;
char care;
unsigned short distance;
int cars;
char letter;
unsigned char quick;
char maelstrom;
unsigned int station;
short rat;
long macey;
float limb; 
} Data;

int compare(const void *pa, const void * pb);

int main(int argc, char** argv) {
    FILE* fp = fopen(argv[1],"rb");
    
    int fn = fileno(fp);
    struct stat sb;
    fstat(fn,&sb);
    
    #define NUM (int)(sb.st_size/sizeof(Data))
    int i;
    Data *arr[NUM];

    for(i = 0; i < NUM; i++) {
        arr[i] = (Data *)malloc(sizeof(Data));
        fread(&arr[i]->dest,sizeof(arr[i] -> dest),1,fp);
        fread(&arr[i]->dec,sizeof(arr[i]->dec),1,fp);
        fread(&arr[i]->colour,sizeof(arr[i]->colour),1,fp);
        fread(&arr[i]->dress,sizeof(arr[i]->dress),1,fp);
        fread(&arr[i]->experience,sizeof(arr[i]->experience),1,fp);
        fread(&arr[i]->voyage,sizeof(arr[i]->voyage),1,fp);
        fread(&arr[i]->care,sizeof(arr[i]->care),1,fp);
        fread(&arr[i]->distance,sizeof(arr[i]->distance),1,fp);
        fread(&arr[i]->cars,sizeof(arr[i]->cars),1,fp);
        fread(&arr[i]->letter,sizeof(arr[i]->letter),1,fp);
        fread(&arr[i]->quick,sizeof(arr[i]->quick),1,fp);
        fread(&arr[i]->maelstrom,sizeof(arr[i]->maelstrom),1,fp);
        fread(&arr[i]->station,sizeof(arr[i]->station),1,fp);
        fread(&arr[i]->rat,sizeof(arr[i]->rat),1,fp);
        fread(&arr[i]->macey,sizeof(arr[i]->macey),1,fp);
        fread(&arr[i]->limb,sizeof(arr[i]->limb),1,fp);
    }
    qsort(arr,NUM,sizeof(Data),compare);
    for(i = 0; i < NUM; i++) {
        printf("%d, ", arr[i]->dest);
    }
    printf("\n");
    for(i = 0; i < NUM; i++) {
        free(arr[i]);
    }
    fclose(fp);
    return 0;
}

int compare (const void * pa, const void * pb)
{
  const Data *p1 = (Data *)pa;
  const Data *p2 = (Data *)pb;
  return ( p1->dest- p2->dest);
}

不是qsort,是你的比较函数。您在 compare.

中输入错误

比较器获取指向数组项的指针,这些项是指向Data结构的指针,而不是Data本身。要正确处理它们,您需要

int compare (const void * pa, const void * pb)
{
    const Data **p1 = (Data **)pa;
    const Data **p2 = (Data **)pb;
    return ( (*p1)->dest- (*p2)->dest);
}

上面的代码有一个小缺陷 - papb 是 'pointers to const something'。强制转换 (Data **)pa 将类型转换为缺少 const 限定符的 'pointer to a pointer to Data'。正确的转换是

  Data * const *p1 = (Data * const *)pa;
  Data * const *p2 = (Data * const *)pb;

这使得 'a pointer to a const pointer to Data'。这声明生成的 p1p2 指针不能用于修改我们数组的项目。

我们可以添加另一个限定符以更加安全:

    const Data * const *p1 = (const Data * const *)pa;
    const Data * const *p2 = (const Data * const *)pb;

将结果指针声明为 'a pointer to a const pointer to const Data' – 不仅数组的项目是不可变的,而且指向的 Data 对象也受到保护以防止更改。