You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:46:45