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

从文件读取数据到链表时sscanf匹配失败问题求助

问题描述

我编写了一段C语言代码,用于从President.txt文件读取总统数据到链表,但始终触发sscanf的错误判定分支。我已多次检查文件内容,确认格式无误,但仍无法正常读取数据。希望能获得问题排查帮助,或相关技术学习知识点我可以自行研究解决。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100

typedef struct President {
    int rno;
    char name[MAX];
    int start_date;
    int end_date;
    struct President *next;
} President;

void readDataFromFile(President **h) {
    FILE *fp = fopen("President.txt", "r");
    if (fp == NULL) {
        printf("Cannot open a file!\n");
        return;
    }

    char buffer[MAX];
    int rno, start_date, end_date;
    char name[MAX];

    while(fgets(buffer, MAX, fp) != NULL) {
        // Reading data from line
        if (sscanf(buffer, "%d %[^\n] %d-%d", &rno, name, &start_date, &end_date) != 4) {
            printf("Error trying to read file!\n");
            fclose(fp);
            return;
        }

        // Creating of new node
        President *newNode = (President*)malloc(sizeof(President));
        if (newNode == NULL) {
            printf("Memory error!\n");
            fclose(fp);
            return;
        }
        newNode->rno = rno;
        strcpy(newNode->name, name);
        newNode->start_date = start_date;
        newNode->end_date = end_date;
        newNode->next = NULL;

        // Adding new node to list
        if (*h == NULL) {
            *h = newNode;
        } else {
            President* current = *h;
            while (current->next != NULL) {
                current = current->next;
            }
            current->next = newNode;
        }
    }

    fclose(fp);
    printf("Data is added to list!\n");
}

文件示例内容

1 President 2000-2004 
2 President 1932-1957 
3 President 2012-2016

问题排查与解决

核心问题

你的sscanf格式串存在两个致命问题:

  1. %[^\n]匹配逻辑错误:该格式符会读取所有字符直到换行符,包括名字后面的空格和日期部分,导致后续的%d-%d完全无法匹配,返回值远小于4,触发错误分支。
  2. 格式串转义错误:原代码中格式串里的 是未正确转义的换行符,实际应该写成\n,不过即使修正了这一点,第一个问题依然存在。

修复方案

方案1:修正sscanf格式串

如果名字是单个单词(无空格),直接用%s匹配名字即可,它会自动在空格处停止:

if (sscanf(buffer, "%d %s %d-%d", &rno, name, &start_date, &end_date) != 4) {
    printf("Error trying to read file!\n");
    fclose(fp);
    return;
}

如果名字包含空格(比如John Adams),需要先清理行尾的换行符,再用更精准的格式串,确保名字读取到日期前的空格为止:

while(fgets(buffer, MAX, fp) != NULL) {
    // 移除行尾的换行符和空白字符
    buffer[strcspn(buffer, "\n")] = '\0';
    // 用%[^0-9]匹配名字(直到遇到数字为止),并跳过后续空白
    if (sscanf(buffer, "%d %[^0-9]%d-%d", &rno, name, &start_date, &end_date) != 4) {
        printf("Error trying to read file!\n");
        fclose(fp);
        return;
    }
    // 清理名字末尾的空格
    name[strcspn(name, " ")] = '\0';
    // 后续节点创建逻辑不变...
}

方案2:用strtok分步分割字符串(更可靠)

对于复杂格式的文本,分步分割比sscanf更可控,避免格式串匹配的歧义:

while(fgets(buffer, MAX, fp) != NULL) {
    buffer[strcspn(buffer, "\n")] = '\0';
    
    // 分割编号
    char *token = strtok(buffer, " ");
    if (!token) goto read_error;
    rno = atoi(token);
    
    // 分割名字(如果名字含空格,需要调整为合并到日期前的所有token)
    token = strtok(NULL, " ");
    if (!token) goto read_error;
    strcpy(name, token);
    
    // 分割日期部分
    token = strtok(NULL, "-");
    if (!token) goto read_error;
    start_date = atoi(token);
    
    token = strtok(NULL, " ");
    if (!token) goto read_error;
    end_date = atoi(token);
    
    // 节点创建与插入逻辑不变...
    continue;

read_error:
    printf("Error trying to read file!\n");
    fclose(fp);
    return;
}

额外排查建议

  • 检查MAX宏的定义是否足够大,确保能容纳文件中最长的一行内容。
  • 确认文件路径正确:如果President.txt不在程序运行的当前工作目录,需要使用绝对路径(比如fopen("/home/user/President.txt", "r"))。
  • 在错误分支中打印当前读取的buffer内容:printf("Failed line: '%s'\n", buffer);,直观看到实际读取的内容,更容易定位匹配失败的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:05:23