如何修复qsort对student结构体数组排序无效的问题
修复qsort对结构体数组按sid排序失效的问题
问题现象
运行代码后,排序前后s[0].sid无变化,qsort未对结构体数组按sid字段进行正确排序。
核心错误
问题出在cmpid比较函数的返回值逻辑上:
return (s1->sid > s2->sid) - (s1->sid > s2->sid);
这个表达式的结果永远是0,因为两个相同的布尔值相减为0。qsort会认为所有元素的排序优先级相同,因此不会执行任何排序操作。
修复方案
修改cmpid函数,返回正确的比较结果。有两种可靠的写法:
写法1(适用于sid不会发生整数溢出的场景)
int cmpid(const void *a, const void *b ) { const struct student* s1 = (const student *) a; const struct student* s2 = (const student *) b; return s1->sid - s2->sid; }
写法2(避免整数溢出,更安全)
int cmpid(const void *a, const void *b ) { const struct student* s1 = (const student *) a; const struct student* s2 = (const student *) b; return (s1->sid > s2->sid) ? 1 : (s1->sid < s2->sid) ? -1 : 0; }
修改后的完整代码
#define BUFC 1024 enum {NSTD = 64, NMARK = 100}; typedef struct student{ int sid; int nmarks; /* number grades */ int marks[NMARK]; /* grades array */ } student; int cmpid(const void *a, const void *b ); int main(int argc, char **argv){ char buf[BUFC]; int i,j, sidx = 0; student s[NSTD] = {{.sid = 0,.marks = 0 }}; FILE *fp = argc > 1 ? fopen(argv[1],"r") : stdin; if(!fp){ fprintf(stderr,"error: file open failed '%s'.\n", argv[1]); return 1; } printf("\nEnter student ID followed by grad (0,100) 101 for next student, 102 when finished.\n"); for(; sidx < NSTD; ){ int grade = 0, tries = 0; int n; int offset; if(!fgets(buf,BUFC,stdin)){ fputs("\n(user canceled input)\n",stdout); break; } buf[strcspn(buf,"\n")] = 0; char *data = buf; while (sscanf(data," %d%n",&n,&offset) == 1) { s[sidx].marks[s[sidx].nmarks++] = n; data = data + offset; } sidx ++; } if(fp != stdin) fclose(fp); for(i = 0; i < sidx; i++){ s[i].sid = s[i].marks[0]; } printf("sidx=%d\n",sidx); for(i = 0; i < 2; i++){ printf("\nStudent ID:%3d\tgrades:",s[i].sid); } putchar('\n'); printf("Before Qsort: s[0].sid=%d\n",s[0].sid); qsort(s,sidx, sizeof *s,cmpid); printf("After Qsort s[0].sid=%d\n",s[0].sid); return 0; } // 修复后的比较函数 int cmpid(const void *a, const void *b ) { const struct student* s1 = (const student *) a; const struct student* s2 = (const student *) b; return (s1->sid > s2->sid) ? 1 : (s1->sid < s2->sid) ? -1 : 0; }
验证效果
重新编译运行命令:gcc array_struct20.c && ./a.out <dat/idmarks.txt
输出会显示排序后s[0].sid变为最小的学生ID(示例中为166),说明qsort已正常生效。
内容的提问来源于stack exchange,提问作者jian
相关产品推荐
相关产品推荐

