繁体   English   中英

qsort分段故障结构

[英]qsort Segmentation Fault structs

所以,我在这里的第一个问题,请耐心等待:

我的任务是对结构体数组进行排序(名称,姓氏和生日的另一个结构体,其中包括年,月,日)。 我必须按生日和使用qsort排序。 我的问题是,我查找了有关qsort的所有内容,但是由于我是C语言新手,所以我不确定我的实现是否正确。我可以创建可执行程序,但它不会给我任何结果,只有Segmentation Fault。

这是我的代码:

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

typedef int (*compfn) (const void*, const void*);

typedef struct {
    unsigned year, month, day;
} date_t;

typedef struct {
    char name[32];
    char surname[32];
    date_t birthday;
}person_t;

typedef struct {
    unsigned n;
    unsigned cap;
    person_t *arr;
} persons_t;


int compare(person_t *a, person_t *b){
  if(a->birthday.year!=b->birthday.year){
    return a->birthday.year-b->birthday.year;
  }else{
    if(a->birthday.month!=b->birthday.month){
      return a->birthday.month-b->birthday.month;
    }else{
      return a->birthday.day-b->birthday.day;
    }
  }
}

int main(int argc, char* argv[])
{
    if (argc <= 1) {
        fprintf(stderr, "syntax: %s <inputfile>\n", argv[0]);
        return 1;
    }

    FILE* f = fopen(argv[1], "rt");
    if (f == NULL) {
        fprintf(stderr, "cannot open file %s\n", argv[1]);
        return 1;
    }

    persons_t persons;
    persons.n = 0;
    persons.cap = 0;
    persons.arr = NULL;

    person_t p;
    while (fscanf(f, "%s %s %4u-%2u-%2u", p.name, p.surname,
            &p.birthday.year, &p.birthday.month, &p.birthday.day) == 5) {

        if (persons.n == persons.cap) {
            persons.cap = persons.cap == 0 ? 1 : 2 * persons.cap;
            persons.arr = realloc(persons.arr, persons.cap * sizeof(persons.arr[0]));
        }

        persons.arr[persons.n++] = p;
    }

    int nitems = persons.cap*sizeof(persons.arr[0]);
    int size = sizeof(persons.arr[0]);
    qsort(persons.arr, nitems, size, (compfn)compare);
    for (unsigned i = 0; i < persons.n; i++) {
        person_t *p = persons.arr + i;
        printf("%s %s %4u-%2u-%2u\n",
                p->name, p->surname,
                p->birthday.year, p->birthday.month, p->birthday.day);
    }



    fclose(f);
    return 0;
}

我希望有人能帮助我,在此先谢谢;)

因此,您可以使用person.cap在需要的时候通过将数组大小加倍来分配数组,但是您并未填充其所有元素,对吗?

根据您的代码,实际人数是nitems = person.n,而不是person.cap。 如果使用nitems = persons.n重试代码怎么办?

如果数组中有未填充的元素,则意味着其中的字符串是任意的(即person.name),因此可能不是以空字符结尾的,并且当您尝试显示它们时会发生崩溃。

_t后缀的标识符而言,根据C标准,它们保留用于实现(例如,编译器和/或标准库)。 您的实现很有可能已经具有date_t类型,并且您的代码可能会引起某种恶作剧。 如果您希望避免对标识符进行微妙和危险的冲突而造成各种破坏,那么最好避免使用它们。 不用担心,您始终可以使用' _s '来表示struct类型!


每当您声明一个表示数组内索引的变量时,请使用size_t作为类型!


 int compare(person_t *a, person_t *b){ 

...

 qsort(persons.arr, nitems, size, (compfn)compare); 

根据qsort手册 ,作为比较器函数给出的参数应为int (*compar)(const void *, const void *) ,这就是将其(compfn)(compfn)以来的(compfn) qsort知道,该函数接受两个const void *参数,这在表示person_t *可能与person_t *参数不同。 这肯定会导致段错误。 不要说谎compare的类型。 将其更改为更像:

int compare(const void *x, const void *y) {
    const person_s *a = x, *b = y;
    /* ... */
}

...,您将不需要强制转换 typedef。

接下来,转到该函数的返回值。 我使用过这样的实现方式,在这种实现方式中,词汇上不合逻辑的返回值会导致分段错误。 例如,如果a <= bb <= c ,则a <= c ,但是您的代码不能保证这一点。 实际上,使用您的代码有可能a <= bb <= ca > c 我建议确保您的代码保证返回值和词法顺序之间的对应关系。 为此,您可以返回大于1的值,等于0的值或小于-1的值。

#define lexical_order(x,y) ((x > y) - (x < y))
int compare(const void *x, const void *b){
  const person_s *a = x, *b = y;
  return a->birthday.year != b->birthday.year   ? lexical_order(a->birthday.year,  b->birthday.year)
       : a->birthday.month != b->birthday.month ? lexical_order(a->birthday.month, b->birthday.month)
                                                : lexical_order(a->birthday.day,   b->birthday.day);
}

我确定您知道应该检查realloc的返回值...例如:

void *temp = realloc(persons.arr, persons.cap * sizeof(persons.arr[0]));
if (temp == NULL) {           /* If we don't check return value prior *
                               * to assigning to persons.arr, we      *
                               * might leak some memory...            */
    puts("Error in realloc");
    free(persons.arr);
    exit(-1);
}
persons.arr = temp;

最后,最重要的是(这可能是您的错误),您确定吗?

int nitems = persons.cap*sizeof(persons.arr[0]);

如果您打算将此作为传递给qsort的项目数(通常),那么我认为应该是:

size_t nitems = persons.n;

PS:如果您第二次错过了它,则可能应该审核代码,以确保您使用size_t仅存储数组索引。

PPS不要忘记free(persons); 在程序的末尾,因此当使用valgrind时,您不会收到关于内存泄漏的valgrind ...

PPPS valgrind很棒!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM