【问题标题】:Segmentation Fault when using qsort on struct in C在 C 中对 struct 使用 qsort 时出现分段错误
【发布时间】:2021-10-31 15:11:06
【问题描述】:

我正在尝试编写一个程序来读取包含多个结构的二进制文件并打印该数据的排序版本,但是每当我尝试运行 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);
}

【问题讨论】:

  • 尝试通过valgrind运行代码定位问题源。
  • 你为什么将arr声明为Data *arr[NUM];

标签: c segmentation-fault qsort


【解决方案1】:

不是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 是“指向 const 某事的指针”。转换 (Data **)pa 将类型转换为“指向指向数据的指针的指针”,它缺少 const 限定符。正确的演员表是

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

这使得'指向const指向数据的指针'。这声明生成的p1p2 指针不能用于修改我们数组的项。

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

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

将生成的指针声明为“指向const 的指针,指向const 数据的指针”——不仅数组的项是不可变的,而且指向的Data 对象也受到保护,不会被更改。

【讨论】:

  • 当我尝试编译代码时,它说 (Data **) pa 是一个不兼容的指针类型
  • @kirinM 你说得对,我在答案中添加了一个修复程序。
  • 棘手。但我觉得无论如何没有指针数组而只有数据会更容易。由于尺寸是预定的
  • @KamiKaze 这绝对是正确的。 :) 即使预先不知道大小或对于自动变量的存储来说太大,我们也可以动态分配Datas 的整个数组。它的执行速度更快(一次分配而不是 500 次,并且与释放相同),使用速度更快(沿数组的偏移量而不是取消引用新指针)和内存效率更高(需要维护一个分配的块)。
猜你喜欢
  • 2020-11-21
  • 2018-02-15
  • 1970-01-01
  • 2020-02-28
  • 1970-01-01
  • 2017-06-01
  • 2021-03-12
  • 2021-06-13
  • 2013-04-03
相关资源
最近更新 更多