如何将操作文件数据传入Insertion Sort排序程序?
解决基于插入排序的文件数据传入与排序问题
你的代码无法将文件数据传入排序程序的根本原因是没有正确存储文件中的多行数据,且排序逻辑存在多处变量、类型、循环条件的错误。以下是具体问题分析和修正方案:
主要问题分析
- 数据存储错误:当前
id[6]、eko[5]等只是单个字符数组,只能存储一行数据的单个字段,无法保存文件中所有行的记录,排序时自然没有可用数据。 - 文件读取逻辑错误:使用
do-while(!feof(af))会导致最后一行数据被重复读取,且读取后仅打印,未将数据存储到可用于排序的数组中。 - 未初始化变量:
n(数据行数)未赋值,排序循环中直接使用会导致未定义行为。 - 类型不匹配:文件中读取的是字符串形式的分数(如"85"),直接作为字符数组比较排序是错误的,需要转换为整数类型才能正确比较大小。
- 排序逻辑错误:循环条件
1<=eko[i]完全不符合插入排序的逻辑,且重新打开文件后未正确读取所有数据到数组。 - 文件操作混乱:局部作用域内重新定义
FILE *af,导致外部文件指针被覆盖,且fclose位置错误,可能引发资源泄漏。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_RECORDS 100 // 假设最多100条记录 // 定义结构体存储每条记录 typedef struct { char id[6]; int eko; int geo; int sos; int sej; } Record; void insertionSortByEko(Record records[], int n) { int i, j; Record key; for (i = 1; i < n; i++) { key = records[i]; j = i - 1; // 按Ekonomi分数降序排序,升序则改为records[j].eko > key.eko while (j >= 0 && records[j].eko < key.eko) { records[j + 1] = records[j]; j = j - 1; } records[j + 1] = key; } } void insertionSortByGeo(Record records[], int n) { int i, j; Record key; for (i = 1; i < n; i++) { key = records[i]; j = i - 1; while (j >= 0 && records[j].geo < key.geo) { records[j + 1] = records[j]; j = j - 1; } records[j + 1] = key; } } void insertionSortBySos(Record records[], int n) { int i, j; Record key; for (i = 1; i < n; i++) { key = records[i]; j = i - 1; while (j >= 0 && records[j].sos < key.sos) { records[j + 1] = records[j]; j = j - 1; } records[j + 1] = key; } } void insertionSortBySej(Record records[], int n) { int i, j; Record key; for (i = 1; i < n; i++) { key = records[i]; j = i - 1; while (j >= 0 && records[j].sej < key.sej) { records[j + 1] = records[j]; j = j - 1; } records[j + 1] = key; } } void printRecords(Record records[], int n) { printf(" | id | eko | geo | sos | sej |\n"); for (int i = 0; i < n; i++) { printf("Data ke-%d : |%s|-|%d|-|%d|-|%d|-|%d|\n", i+1, records[i].id, records[i].eko, records[i].geo, records[i].sos, records[i].sej); } } int main() { FILE *af = fopen("modul.txt", "r"); if (af == NULL) { printf("无法打开文件 modul.txt\n"); return 1; } Record records[MAX_RECORDS]; int n = 0; char id[6], eko_str[5], geo_str[5], sos_str[5], sej_str[5]; printf("DATA NILAI UTBK SOSHUM 2019\n"); // 正确读取所有记录到数组 while (fscanf(af, "%s %s %s %s %s", id, eko_str, geo_str, sos_str, sej_str) == 5) { strcpy(records[n].id, id); records[n].eko = atoi(eko_str); records[n].geo = atoi(geo_str); records[n].sos = atoi(sos_str); records[n].sej = atoi(sej_str); n++; if (n >= MAX_RECORDS) { printf("记录数量超过上限,停止读取\n"); break; } } fclose(af); // 打印原始数据 printRecords(records, n); char pil; do { printf("\nMengurutkan nilai TKA Soshum UTBK 2019\n"); printf("1. Nilai Ekonomi\n"); printf("2. Nilai Geografi\n"); printf("3. Nilai Sosiologi\n"); printf("4. Nilai Sejarah\n"); printf("5. Keluar\n"); printf("Masukkan Pilihan : "); // 处理输入缓冲区的换行符 while ((pil = getchar()) == '\n'); switch(pil) { case '1': printf("\nNilai Ekonomi (Terurut)\n"); insertionSortByEko(records, n); printRecords(records, n); break; case '2': printf("\nNilai Geografi (Terurut)\n"); insertionSortByGeo(records, n); printRecords(records, n); break; case '3': printf("\nNilai Sosiologi (Terurut)\n"); insertionSortBySos(records, n); printRecords(records, n); break; case '4': printf("\nNilai Sejarah (Terurut)\n"); insertionSortBySej(records, n); printRecords(records, n); break; case '5': printf("Keluar程序\n"); return 0; default: printf("\nSalah Masukkan Pilihan, Ulangi Lagi!\n"); } } while(1); return 0; }
关键修改说明
- 使用结构体存储记录:定义
Record结构体,将每条记录的id和各科分数统一存储,方便管理和排序。 - 正确读取文件数据:用
while(fscanf(...) ==5)判断读取是否成功,避免feof的陷阱,同时将字符串形式的分数转换为整数(atoi)。 - 分离排序函数:将不同科目的插入排序逻辑封装为独立函数,代码更清晰易维护。
- 修复输入处理:用
while((pil=getchar())=='\n')处理输入缓冲区的换行符,避免无效输入。 - 添加文件错误检查:判断
fopen是否成功,避免空指针访问。
内容的提问来源于stack exchange,提问作者cllgdmp
相关产品推荐
相关产品推荐

