[英]qsort Segmentation Fault structs
So, my first question here, please be patient with me: 所以,我在这里的第一个问题,请耐心等待:
My task is to sort an array of structs (name, surname and another struct for the birthday, which consists of the year, month, day). 我的任务是对结构体数组进行排序(名称,姓氏和生日的另一个结构体,其中包括年,月,日)。 I have to sort by birthdate and by using qsort.
我必须按生日和使用qsort排序。 My problem is, I looked up everything about qsort but i am not quite sure if my implementation is correct since I am new to C. I can create the executable program but it is not giving my any result only Segmentation Fault.
我的问题是,我查找了有关qsort的所有内容,但是由于我是C语言新手,所以我不确定我的实现是否正确。我可以创建可执行程序,但它不会给我任何结果,只有Segmentation Fault。
Here is my Code: 这是我的代码:
#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;
}
I hope someone can help me, Thanks in advance ;) 我希望有人能帮助我,在此先谢谢;)
So you are allocating our array by doubling its size whenever needed, using persons.cap, but you are not filling all its elements, are you? 因此,您可以使用person.cap在需要的时候通过将数组大小加倍来分配数组,但是您并未填充其所有元素,对吗?
From your code, the actual number of persons is nitems = persons.n, not persons.cap. 根据您的代码,实际人数是nitems = person.n,而不是person.cap。 What if you retry your code with nitems=persons.n?
如果使用nitems = persons.n重试代码怎么办?
If you have unfilled elements in your array, it means the strings inside them are arbitrary (ie person.name), so probably not null-terminated, and the crash will occur when you try to display them. 如果数组中有未填充的元素,则意味着其中的字符串是任意的(即person.name),因此可能不是以空字符结尾的,并且当您尝试显示它们时会发生崩溃。
As far as _t
-suffixed identifiers go, according to the C standard they're reserved for the implementation (eg your compiler, and/or your standard library). 就
_t
后缀的标识符而言,根据C标准,它们保留用于实现(例如,编译器和/或标准库)。 It's very possible that your implementation already has a date_t
type, and your code might be causing some kind of mischief. 您的实现很有可能已经具有
date_t
类型,并且您的代码可能会引起某种恶作剧。 If you wish to avoid subtly and dangerously clashing identifiers wreaking all sorts of havoc, it's probably best to avoid them. 如果您希望避免对标识符进行微妙和危险的冲突而造成各种破坏,那么最好避免使用它们。 Not to worry, you could always use '
_s
' to denote a struct
type instead! 不用担心,您始终可以使用'
_s
'来表示struct
类型!
Whenever you're declaring a variable that represents an index within an array, use size_t
as the type! 每当您声明一个表示数组内索引的变量时,请使用
size_t
作为类型!
int compare(person_t *a, person_t *b){
...
...
qsort(persons.arr, nitems, size, (compfn)compare);
According to the qsort manual , the argument given as the comparator function should be an int (*compar)(const void *, const void *)
, and that's what you've given since you've cast to (compfn)
. 根据qsort手册 ,作为比较器函数给出的参数应为
int (*compar)(const void *, const void *)
,这就是将其(compfn)
为(compfn)
以来的(compfn)
。 As far as qsort
is aware that function accepts two const void *
arguments, which might differ in representation to person_t *
arguments. 据
qsort
知道,该函数接受两个const void *
参数,这在表示person_t *
可能与person_t *
参数不同。 This could certainly cause segfaults. 这肯定会导致段错误。 Don't lie about the type of
compare
. 不要说谎
compare
的类型。 Change it to look more like: 将其更改为更像:
int compare(const void *x, const void *y) {
const person_s *a = x, *b = y;
/* ... */
}
... and you won't need the cast or the typedef. ...,您将不需要强制转换或 typedef。
Next, onto return values for that function. 接下来,转到该函数的返回值。 I have used implementations where-by lexically illogical return values cause segmentation faults.
我使用过这样的实现方式,在这种实现方式中,词汇上不合逻辑的返回值会导致分段错误。 For example, if
a <= b
and b <= c
, then a <= c
, but your code doesn't guarantee this. 例如,如果
a <= b
和b <= c
,则a <= c
,但是您的代码不能保证这一点。 In fact, using your code it is possible that a <= b
, b <= c
and a > c
. 实际上,使用您的代码有可能
a <= b
, b <= c
和a > c
。 I recommend making sure your code guarantees correspondence between the return value and lexical order. 我建议确保您的代码保证返回值和词法顺序之间的对应关系。 You can do so by returning 1 for greater than, 0 for equal to or -1 for less than.
为此,您可以返回大于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);
}
I'm sure you're aware that you should be checking the return value of realloc
... For example: 我确定您知道应该检查
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;
Finally, and most importantly (this is probably your error), are you sure about this? 最后,最重要的是(这可能是您的错误),您确定吗?
int nitems = persons.cap*sizeof(persons.arr[0]);
If you mean to pass this as the number of items to qsort
(which is usual), then I think that should be: 如果您打算将此作为传递给
qsort
的项目数(通常),那么我认为应该是:
size_t nitems = persons.n;
PS In case you missed it the second time, you should probably audit your code to make sure you're using size_t
to store array indexes only. PS:如果您第二次错过了它,则可能应该审核代码,以确保您使用
size_t
仅存储数组索引。
PPS Don't forget to free(persons);
PPS不要忘记
free(persons);
at the end of your program, so you don't end up with reports of memory leaks when you use valgrind
... 在程序的末尾,因此当使用
valgrind
时,您不会收到关于内存泄漏的valgrind
...
PPPS valgrind
is awesome! PPPS
valgrind
很棒!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.