C语言文件读取问题:仅读取首行数据,求指导修正
问题分析与修正方案
我仔细看了你的代码,确实存在几个导致读取文件时只能拿到首行数据的问题,下面逐个拆解并给出修复后的完整代码:
核心问题点
1. feof() 的错误使用
你打印函数里的 while (!feof(q)) 是典型的误用——feof() 并不会在文件指针到达末尾时立即返回真,而是在尝试读取超出文件末尾之后才会置位。这就导致当最后一次fscanf读取失败(返回-1)时,你仍然会执行printf,而且循环不会及时终止。正确的做法是直接用fscanf的返回值来控制循环:当它成功读取到指定数量的变量时(这里是3个),才继续执行后续逻辑。
2. 文件写入时重复打开未及时关闭的问题
在main函数的录入循环里,你每次都用"a"模式打开文件,但只在循环结束后才关闭一次。这种重复打开文件的操作不仅效率低,还可能导致缓冲区数据未及时刷新到磁盘,读取时就会出现数据不完整的情况。更好的做法是只打开一次文件,循环写入所有数据后再关闭。
3. 结构体typedef的语法错误
你的结构体定义顺序颠倒了,正确的typedef结构体写法应该是:
typedef struct studnt { // 成员 } s_studnt;
原来的写法会导致编译警告,甚至可能出现未定义的类型问题。
4. 内存分配的优先级问题
在给学生名字分配内存时:
studnt[i].name = (char*)malloc(length+1 * sizeof(char));
这里的运算符优先级有问题——*的优先级高于+,所以实际计算的是length + (1 * sizeof(char)),虽然sizeof(char)是1,结果暂时没问题,但写法不规范,容易在其他场景出错,应该改成(length + 1) * sizeof(char)。
5. 打印函数的冗余参数
print_studnt函数里的FILE *q参数完全没用,因为你在函数内部重新fopen了文件,直接去掉这个参数更清晰。
修复后的完整代码
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> // 修正typedef的写法 typedef struct studnt { int id; int number; char *name; } s_studnt; // 去掉冗余的FILE*参数 void print_studnt(char name_file[]) { int id, number; char str_name[20]; FILE *q = fopen(name_file, "r"); if (q == NULL) { printf("error fopen\n"); return; } printf("\n"); // 用fscanf的返回值控制循环:成功读取3个变量才继续 while (fscanf(q, "%d %s %d", &id, str_name, &number) == 3) { printf("student name:%s\nstudent id:%d\ntelephone number:%d\n", str_name, id, number); printf("\n"); } fclose(q); return; } int main() { int size, i, length; char str[20], name_file[20]; FILE *q = NULL; s_studnt *studnt = NULL; printf("how many students do you have:\n"); scanf("%d", &size); studnt = (s_studnt*)malloc(size * sizeof(s_studnt)); if (studnt == NULL) { printf("error: memory allocation failed\n"); return 0; } printf("enter file name:\n"); scanf("%s", name_file); // 只打开一次文件,循环写入所有数据 q = fopen(name_file, "w"); if (q == NULL) { printf("error: cannot open file for writing\n"); free(studnt); // 避免内存泄漏 return 0; } for (i = 0; i < size; i++) { printf("enter student name:\n"); scanf("%s", str); length = strlen(str); // 修正内存分配的优先级问题 studnt[i].name = (char*)malloc((length + 1) * sizeof(char)); if (studnt[i].name == NULL) { printf("error: memory allocation for name failed\n"); // 释放已分配的内存,避免泄漏 for (int j = 0; j < i; j++) { free(studnt[j].name); } free(studnt); fclose(q); return 0; } strcpy(studnt[i].name, str); printf("enter student id:\n"); scanf("%d", &studnt[i].id); printf("enter telephone number:\n"); scanf("%d", &studnt[i].number); // 直接写入已打开的文件 fprintf(q, "%d %s %d\n", studnt[i].id, studnt[i].name, studnt[i].number); } fclose(q); // 释放学生结构体的内存(避免内存泄漏) for (i = 0; i < size; i++) { free(studnt[i].name); } free(studnt); print_studnt(name_file); return 0; }
额外优化点
- 增加了内存泄漏防护:在分配失败时释放已分配的内存,避免内存泄漏。
- 修正了一些拼写错误(比如
studnt→student,eror→error),提升代码可读性。 - 写入文件时只打开一次,减少IO操作的开销。
这样修改后,就能正常读取并打印所有学生的信息了。
内容的提问来源于stack exchange,提问作者aviv.L
相关产品推荐
相关产品推荐

