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

C语言读取特定格式TXT文件并写入队列时异常问题排查

问题排查:从TXT文件加载队列数据失败

问题背景

目标TXT文件格式

11/01/2010: did not pass the test! :(
5
10/02/2010: not even this time I passed it! >:(
2
16/04/2010: is the third time I retake this exam!!! >:@
1
20/05/2024: finally passed it! :D 
14

队列数据结构定义

#define N_QUEUE 4
#define OK 0
#define FILE_ERR 1
#define EMPTY 2
#define FULL 3
#define FALSE 1

struct post {
    char msg[257];
    int n_like;
};

struct feed {
    struct post* storage;
    int busy;
};

void init(struct feed* queue) {
    queue->storage = malloc(sizeof(struct post) * N_QUEUE);
    queue->busy = 0;
}

现有实现代码

队列操作函数

int append(struct feed* queue, struct post s) {
    if (queue->busy >= N_QUEUE) return handle_err(FULL);
    queue->storage[queue->busy] = s;
    queue->busy++;
    return OK;
}

struct post pop(struct feed* queue) {
    if (queue->busy <= 0) handle_err(EMPTY);
    struct post s = queue->storage[0];
    for (int i=0; i<queue->busy-1; i++) {
        queue->storage[i] = queue->storage[i+1];
    }
    queue->busy--;
    return s;
}

文件加载函数(存在问题)

int load_user_from_file(char* filename, struct feed* queue) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) return handle_err(FILE_ERR);
    
    struct post s;
    while (fgets(s.msg, 257, fp) != NULL) {
            while (fscanf(fp, "%d", &s.n_like) == 1) {
                append(&(*queue), s);
            }
        }
    return OK;
}

主函数

int main() {
    struct feed queue;
    init(&queue);
    char* filename = "user42.txt";
    load_user_from_file(filename, &queue);

    return 0;
}

错误处理函数

int handle_err(int errno) {
    switch (errno) {
        case FILE_ERR:
            printf("\nerror (%d): could not write/read the file\n\n", FILE_ERR);
            break;
        case EMPTY:
            printf("\nerror (%d): queue is empty\n\n", EMPTY);
            break;
        case FULL:
            printf("\nerror (%d): queue reached its full space\n\n", FULL);
            break;
        default: printf("\nunknown error occurred\n\n");
    }
    exit(FALSE);
}

错误现象

运行程序后队列中得到空字符串和0;加入handle_err后触发栈错误。

问题分析

load_user_from_file函数及关联代码存在三个核心问题:

  • 内层while循环逻辑错误:每个消息行对应一个点赞数,不需要内层循环。当fscanf读取到第一个点赞数后,会尝试继续读取下一个,但下一个内容是消息行,fscanf("%d")匹配失败,此时文件指针停在消息行起始位置,后续fgets会读取残缺内容,导致数据混乱。
  • 未处理fgets读取的换行符:fgets会把换行符\n读入msg数组,导致消息内容包含多余换行,甚至影响后续字符串处理。
  • handle_err参数名冲突:参数名errno是系统标准宏(定义在<errno.h>),使用它会导致命名冲突,引发未定义行为。

修复方案

修正后的load_user_from_file函数

int load_user_from_file(char* filename, struct feed* queue) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) return handle_err(FILE_ERR);
    
    struct post s;
    while (fgets(s.msg, 257, fp) != NULL) {
        // 去掉fgets读取的换行符
        size_t len = strlen(s.msg);
        if (len > 0 && s.msg[len-1] == '\n') {
            s.msg[len-1] = '\0';
        }

        // 读取对应的点赞数,单次读取即可
        int scan_result = fscanf(fp, "%d", &s.n_like);
        if (scan_result != 1) {
            fprintf(stderr, "Failed to read like count for message: %s\n", s.msg);
            break;
        }

        // 跳过点赞数后面的换行符,避免下一次fgets读取空行
        int c;
        while ((c = fgetc(fp)) != '\n' && c != EOF);

        // 将帖子加入队列
        append(queue, s);
    }

    fclose(fp);
    return OK;
}

修正handle_err参数名

int handle_err(int err_code) { // 将errno改为err_code,避免系统宏冲突
    switch (err_code) {
        case FILE_ERR:
            printf("\nerror (%d): could not write/read the file\n\n", FILE_ERR);
            break;
        case EMPTY:
            printf("\nerror (%d): queue is empty\n\n", EMPTY);
            break;
        case FULL:
            printf("\nerror (%d): queue reached its full space\n\n", FULL);
            break;
        default: printf("\nunknown error occurred\n\n");
    }
    exit(FALSE);
}

额外优化建议

  1. 释放内存:在main函数结束前,用free(queue.storage)释放init中分配的内存,避免内存泄漏。
  2. append函数简化:handle_err会直接调用exit,因此return handle_err(FULL)可简化为handle_err(FULL),无需return语句。
  3. pop函数语法补全:虽然handle_err会退出程序,但为了语法完整,可在handle_err后添加return (struct post){0};(需C99及以上标准支持)。

验证

修复后运行程序,队列会正确加载TXT文件中的4条记录,每条记录的消息内容和点赞数与文件完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 12:08:07