C语言期末救急手把手教你用结构体搞定CSU OJ水果店排序题附完整代码临近期末C语言课程设计或OJ平台的编程题往往成为许多同学的拦路虎。特别是涉及结构体、排序算法等综合应用的题目常常让人望而生畏。本文将以中南大学CSU OJ平台中的水果店题目为例带你从零开始一步步攻克这类结构化数据处理难题。这道题看似复杂实则完美展现了结构体在现实场景中的应用价值。我们将从最基础的结构体定义开始逐步深入到数据分类、多条件排序等核心环节最后给出完整的代码实现和调试技巧。无论你是C语言初学者还是对结构体应用不够熟练的同学都能通过这个案例举一反三掌握同类题目的解题思路。1. 理解题目需求与数据结构设计水果店题目要求我们处理一组交易记录每条记录包含水果名称、产地和销售数量。最终需要按产地分类并按字母序排列产地和水果名称同时合并相同产地相同水果的销售数量。这类问题天然适合用结构体来解决。我们先分析需要存储哪些数据#define MAX_NAME_LEN 80 #define MAX_RECORDS 100 struct FruitRecord { char name[MAX_NAME_LEN]; // 水果名称 char area[MAX_NAME_LEN]; // 产地 int quantity; // 销售数量 };关键设计考虑字符串长度根据题目要求设为80字符使用固定大小数组而非指针简化内存管理quantity使用int类型满足题目要求提示在OJ题目中明确数据范围后使用固定大小数组通常比动态分配更安全可靠。2. 输入处理与数据读取题目输入格式为首行是日期和记录数随后每行是一条交易记录。我们需要正确处理这种混合类型输入int year, month, day, n; while (scanf(%d/%d/%d %d, year, month, day, n) ! EOF) { struct FruitRecord records[MAX_RECORDS]; for (int i 0; i n; i) { scanf(%s %s %d, records[i].name, records[i].area, records[i].quantity); } // 后续处理... }常见陷阱日期输入中的/分隔符容易被忽略字符串和整数的混合输入要注意格式字符串数组越界问题确保不超过MAX_RECORDS3. 多级排序算法实现题目要求先按产地字母序排序同产地再按水果名称排序。这需要实现多级排序// 比较函数先按产地再按名称 int compareRecords(const void *a, const void *b) { struct FruitRecord *ra (struct FruitRecord *)a; struct FruitRecord *rb (struct FruitRecord *)b; int area_cmp strcmp(ra-area, rb-area); if (area_cmp ! 0) return area_cmp; return strcmp(ra-name, rb-name); } // 使用qsort进行排序 qsort(records, n, sizeof(struct FruitRecord), compareRecords);性能考虑使用标准库的qsort而非手写冒泡排序效率更高比较函数要正确处理多级比较逻辑对于大型数据集可考虑更高效的排序算法4. 数据合并与统计排序后相邻记录如果是同产地同水果需要合并数量for (int i 1; i n; i) { if (strcmp(records[i].area, records[i-1].area) 0 strcmp(records[i].name, records[i-1].name) 0) { records[i].quantity records[i-1].quantity; records[i-1].quantity 0; // 标记为已合并 } }合并逻辑要点必须在排序后进行确保相同记录相邻使用quantity0标记已合并记录注意数组边界条件5. 格式化输出实现按要求格式输出结果包括日期转换和树状结构printf(%d.%02d.%02d\n, year, month, day); char currentArea[MAX_NAME_LEN] ; for (int i 0; i n; i) { if (records[i].quantity 0) continue; // 新产地时输出产地标题 if (strcmp(records[i].area, currentArea) ! 0) { strcpy(currentArea, records[i].area); printf(%s\n, currentArea); } printf(|----%s(%d)\n, records[i].name, records[i].quantity); }输出细节日期格式转换2022/12/18 → 2022.12.18使用%02d确保月份/日期两位显示树状结构使用|----前缀跳过quantity0的已合并记录6. 完整代码实现与优化将上述模块组合得到完整解决方案#include stdio.h #include string.h #include stdlib.h #define MAX_NAME_LEN 80 #define MAX_RECORDS 100 struct FruitRecord { char name[MAX_NAME_LEN]; char area[MAX_NAME_LEN]; int quantity; }; int compareRecords(const void *a, const void *b) { struct FruitRecord *ra (struct FruitRecord *)a; struct FruitRecord *rb (struct FruitRecord *)b; int area_cmp strcmp(ra-area, rb-area); if (area_cmp ! 0) return area_cmp; return strcmp(ra-name, rb-name); } int main() { int year, month, day, n; while (scanf(%d/%d/%d %d, year, month, day, n) ! EOF) { struct FruitRecord records[MAX_RECORDS]; // 读取输入 for (int i 0; i n; i) { scanf(%s %s %d, records[i].name, records[i].area, records[i].quantity); } // 排序 qsort(records, n, sizeof(struct FruitRecord), compareRecords); // 合并相同记录 for (int i 1; i n; i) { if (strcmp(records[i].area, records[i-1].area) 0 strcmp(records[i].name, records[i-1].name) 0) { records[i].quantity records[i-1].quantity; records[i-1].quantity 0; } } // 输出结果 printf(%d.%02d.%02d\n, year, month, day); char currentArea[MAX_NAME_LEN] ; for (int i 0; i n; i) { if (records[i].quantity 0) continue; if (strcmp(records[i].area, currentArea) ! 0) { strcpy(currentArea, records[i].area); printf(%s\n, currentArea); } printf(|----%s(%d)\n, records[i].name, records[i].quantity); } } return 0; }优化方向增加输入验证防止非法输入使用更高效的数据结构如哈希表进行统计添加错误处理机制模块化设计提高代码可读性7. 调试技巧与常见问题在实现过程中可能会遇到以下典型问题问题1排序结果不正确检查比较函数逻辑确保先比较产地再比较名称验证qsort调用参数是否正确测试边界情况单条记录、空输入等问题2合并数量出错确认排序已完成且正确检查合并条件判断strcmp返回0表示相等验证合并后的quantity是否被正确清零问题3输出格式不符合要求特别注意日期格式转换检查树状结构前缀|----验证是否跳过了已合并记录(quantity0)调试建议使用小样本测试如题目中的样例添加临时打印语句检查中间结果分模块测试先测试排序再测试合并对比样例输出逐行检查差异在实际OJ提交时如果遇到Wrong Answer可以按照以下步骤排查检查样例输入是否能产生正确输出测试边界条件n1, n100验证长字符串处理是否正确检查内存使用避免数组越界掌握这些调试技巧不仅能解决这道题也能应对其他OJ题目的调试需求。结构体相关的题目往往考察综合能力通过这道题的练习你已经在以下方面得到了提升结构体的定义和使用多级排序的实现复杂数据的处理与统计格式化输出的控制调试技巧的实践应用将这些知识点融会贯通就能轻松应对期末考试和OJ平台上的各类结构体相关题目。