C语言姓名列表元素处理:排序异常问题求助
问题分析与修复方案
核心问题根源
你的排序异常和错误值输出主要由以下几个关键错误导致:
- 结构体定义错误:
num被声明为int num[10];,但实际上每个条目只需要一个编号(单个整数)。数组类型导致存储和读取逻辑完全错误,打印时输出的是数组地址而非实际数值,排序时比较的是指针地址差而非编号大小。 - 输入处理混乱:
sscanf重复写入name字段,同时手动解析字符串的逻辑既冗余又未给字符串添加终止符,引发strlen、strcmp等函数的未定义行为。 - qsort 使用错误:在嵌套循环中多次调用
qsort完全没必要,只需在所有数据输入完成后调用一次即可。 - 唯一名字统计逻辑错误:当前逻辑仅当后续没有重复名字时才计数,无法正确统计所有唯一名字的数量。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> // 修正结构体:num改为单个整数,符合需求 struct people { int num; char surname[20]; char name[10]; } peoples[10]; // 修正比较函数:比较单个整数的大小 int compare_people_num(const void *a, const void *b) { const struct people *p1 = (const struct people *)a; const struct people *p2 = (const struct people *)b; return p1->num - p2->num; // 升序排序,反转则返回p2->num - p1->num } int main() { int i, j, unique_count = 0; float avg_surname_len = 0.0f; char str[100]; // 标记名字是否已被统计过 int name_seen[10] = {0}; system("chcp 1251 > nul"); // 输入10组数据,使用sscanf直接解析,避免手动解析的错误 for (i = 0; i < 10; i++) { printf("Enter number, surname, name %d of your human: ", i + 1); fgets(str, sizeof(str), stdin); // 正确解析编号、姓氏、名字到对应字段 sscanf(str, "%d %s %s", &peoples[i].num, peoples[i].surname, peoples[i].name); } // 统计唯一名字数量 for (i = 0; i < 10; i++) { if (!name_seen[i]) { unique_count++; // 标记所有相同的名字为已统计 for (j = i + 1; j < 10; j++) { if (strcmp(peoples[i].name, peoples[j].name) == 0) { name_seen[j] = 1; } } } // 累加姓氏长度 avg_surname_len += strlen(peoples[i].surname); } // 仅调用一次qsort完成排序 qsort(peoples, 10, sizeof(struct people), compare_people_num); // 输出排序后的列表 printf("\nSorted list:\n"); for (i = 0; i < 10; i++) { printf("%d %s %s\n", peoples[i].num, peoples[i].surname, peoples[i].name); } // 输出统计结果 printf("\nYou have %d different names\n", unique_count); printf("Average length of surname is = %.2f\n", avg_surname_len / 10); return 0; }
关键修复点说明
- 结构体修正:将
num改为单个整数,确保编号的存储和读取正确。 - 比较函数修正:直接比较两个
num的整数值,符合排序逻辑。 - 输入逻辑简化:移除冗余的手动字符串解析,使用
sscanf直接将输入映射到结构体字段,避免错误。 - qsort 优化:仅在数据全部输入后调用一次
qsort,提升效率并避免重复排序的问题。 - 唯一名字统计修正:使用
name_seen数组标记已统计的名字,确保每个唯一名字只被计数一次。 - 字符串安全:
sscanf读取字符串时会自动添加终止符,避免strlen和strcmp的未定义行为。
内容的提问来源于stack exchange,提问作者Morkovka
相关产品推荐
相关产品推荐

