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

使用fscanf()读取文件到链表时,变量均为空或0的问题求助

问题分析与解决方案

核心原因:文件指针位置错误

你的代码中readSize函数会遍历整个文件统计行数,这会将文件指针移动到文件末尾(EOF)。后续调用fscanf时,指针已经处于末尾,没有数据可读,导致结构体中的字段始终处于未正确赋值的状态(表现为空字符串或0)。

修复方案

方案1:重置文件指针到开头

在统计行数后,调用rewind(fp)或fseek(fp, 0, SEEK_SET)将文件指针移回文件起始位置,让fscanf能正常读取数据。修改后的readFile函数如下:

int readFile(char *file, struct profile** head) {
    FILE *fp = fopen(file, "r");
    if (fp == NULL) return ERR;
    int lines = readSize(fp);
    
    // 重置文件指针到文件开头
    rewind(fp);
    
    struct profile *curr, *prev;
    curr = prev = NULL;
    
    for (int i=0; i<lines; i++) {
        curr = malloc(sizeof(struct profile));
        // 检查内存分配是否成功
        if (curr == NULL) {
            fclose(fp);
            return ERR;
        }
        // 检查fscanf是否成功读取4个字段
        int ret = fscanf(fp, "%s%s%d%d", curr->name, curr->lname, &curr->weight, &curr->height);
        if (ret != 4) {
            free(curr);
            fclose(fp);
            return ERR;
        }
        curr->next = NULL;
        if (i == 0) *head = curr;
        else prev->next = curr;
        prev = curr;
    }
    fclose(fp);
    return OK;
}

方案2:无需提前统计行数(更高效)

没必要先遍历文件统计行数,直接循环读取直到fscanf返回EOF(文件末尾)即可,这样能避免两次遍历文件,提升效率。修改后的readFile函数如下:

int readFile(char *file, struct profile** head) {
    FILE *fp = fopen(file, "r");
    if (fp == NULL) return ERR;
    struct profile *curr, *prev = NULL;
    *head = NULL;
    
    while (1) {
        curr = malloc(sizeof(struct profile));
        if (curr == NULL) {
            // 内存分配失败,清理已分配节点避免泄漏
            freeNode(head);
            fclose(fp);
            return ERR;
        }
        // 尝试读取一组数据
        int ret = fscanf(fp, "%s%s%d%d", curr->name, curr->lname, &curr->weight, &curr->height);
        if (ret == EOF) {
            // 到达文件末尾,释放当前空节点
            free(curr);
            break;
        }
        if (ret != 4) {
            // 数据格式错误,清理资源
            free(curr);
            freeNode(head);
            fclose(fp);
            return ERR;
        }
        curr->next = NULL;
        if (*head == NULL) {
            *head = curr;
        } else {
            prev->next = curr;
        }
        prev = curr;
    }
    fclose(fp);
    return OK;
}

使用该方案可以直接删除readSize函数。

其他优化点

  1. 内存分配检查:必须检查malloc的返回值,避免内存不足导致程序崩溃。
  2. 读取结果校验:每次调用fscanf后检查返回值,确保成功读取预期的4个字段,避免格式错误导致的垃圾数据。
  3. 内存泄漏修复:在读取过程中发生错误时,要释放已分配的节点,避免内存泄漏。
  4. freeNode函数修正:原函数中head = NULL;仅修改了局部指针,不会影响外部变量,应改为*head = NULL;:
void freeNode(struct profile** head) {
    struct profile* curr = *head;
    while (curr != NULL) {
        struct profile* next = curr->next;
        free(curr);
        curr = next;
    }
    *head = NULL; // 修正此处
}

内容的提问来源于stack exchange,提问作者sansarc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:55:05