如何正确使用fgets从文件逐行读取内容并存入pokemon结构体数组?
Pokemon结构体文件读写:修复readfile函数问题
需求说明
需要实现两个函数:
writefile:将pokemon结构体数组的内容写入文件,格式为每行交替存储等级和名称,例如:
30
Pikachu
12
Charizard
readfile:从上述格式的文件中逐行读取,将数据还原到pokemon结构体数组中
当前readfile函数的错误点
- 错误使用
feof作为循环条件:feof仅在读取操作失败后才会触发,会导致循环多执行一次,读取无效数据 - 直接用
fgets写入int类型变量:pokearray[i].level是int类型,fgets只能读取字符串,直接赋值会导致内存错误 - 无效代码:
pokearray[10].level;这行没有任何实际作用,属于冗余代码 - 未处理名字读取:循环只尝试读取等级,完全忽略了名称的读取逻辑
- 未递增索引
i:循环中没有更新i,所有数据会覆盖到同一个结构体位置 - 未更新
num参数:没有将实际读取到的宝可梦数量返回给调用者 - 未处理读取失败的情况:没有判断
fgets的返回值,无法提前终止循环
修复后的readfile函数
#include <stdio.h> #include <string.h> #include <stdlib.h> struct pokemon { int level; char name[30]; }; int readfile(struct pokemon pokearray[], int* num, char filename[]) { FILE *fp; int i = 0; char level_buf[20]; // 临时存储读取到的等级字符串 fp = fopen(filename, "r"); if (fp == NULL) { printf("打开文件失败"); return -1; } // 循环读取每组(等级+名称)数据,直到读取失败或数组满 while (i < 10) // 假设pokearray最多存储10个元素,可根据实际调整 { // 读取等级字符串 if (fgets(level_buf, sizeof(level_buf), fp) == NULL) break; // 移除字符串末尾的换行符 level_buf[strcspn(level_buf, "\n")] = '\0'; // 转换为int类型赋值给level pokearray[i].level = atoi(level_buf); // 读取名称 if (fgets(pokearray[i].name, sizeof(pokearray[i].name), fp) == NULL) break; // 移除名称末尾的换行符 pokearray[i].name[strcspn(pokearray[i].name, "\n")] = '\0'; i++; } *num = i; // 将实际读取到的数量返回给调用者 fclose(fp); return 0; }
关键修复说明
- 替换循环条件:通过判断
fgets的返回值终止循环,避免feof的坑 - 等级读取处理:先用临时字符串存储读取到的等级,再通过
atoi转换为int类型 - 移除换行符:使用
strcspn自动定位换行符位置并替换为结束符,避免结构体中存储多余的换行 - 完整读取逻辑:每次循环读取一组等级和名称,确保每个结构体对应一条完整的宝可梦数据
- 数组越界保护:添加
i < 10的判断,防止超出结构体数组的容量 - 返回读取数量:通过
num指针将实际读取到的宝可梦个数传递给调用者
配套writefile函数示例
int writefile(struct pokemon pokearray[], int num, char filename[]) { FILE *fp = fopen(filename, "w"); if (fp == NULL) { printf("打开文件失败"); return -1; } for (int i = 0; i < num; i++) { fprintf(fp, "%d\n", pokearray[i].level); fprintf(fp, "%s\n", pokearray[i].name); } fclose(fp); return 0; }
内容的提问来源于stack exchange,提问作者Isaiah Dela Cruz
相关产品推荐
相关产品推荐

