从文件读取日期到链表

Reading dates from file to linked list

提问人:Poizone 提问时间:10/6/2023 最后编辑:chqrliePoizone 更新时间:10/6/2023 访问量:120

问:

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");
}

你好。我正在尝试从文件读取到链表,但我总是收到 if(sscanf) 的错误原因。我的代码有什么问题?我已经检查了几次文件中的文本,但没关系,但无论如何都无法阅读。我能得到一些帮助或一些有用的链接吗?如果您显示我可以在哪里阅读它,我准备自己管理它。

以下是输入文件中的三行示例行

1 President 2000-2004 
2 President 1932-1957 
3 President 2012-2016
C 链表 扫描 fgets

评论

0赞 Scott Hunter 10/6/2023
通过了解文件中的内容来诊断从文件中读取的问题会容易得多。
1赞 greg spears 10/6/2023
“%[^\n]” 将允许 sscanf() 读取所有字符,直到到达 '\n'(换行符标记行尾)。我认为这消耗了生产线的其余部分,没有留下任何start_date和end_date。如果 sscanf() 正好返回 2,那么这可能表明这就是问题所在。
0赞 Weather Vane 10/6/2023
请从文件中发布三行。如果所有项目都是空格分隔的,则需要进行一些分析,以确定名称中是否包含一个、两个或多个空格。
0赞 Eric Postpischil 10/6/2023
编辑问题以提供最小的可重现示例
0赞 Weather Vane 10/6/2023
...请用英语提供节目评论和回复。

答:

1赞 greg spears 10/6/2023 #1

我对您的代码的测试表明,正则表达式 %[^\n] 占用了该行的其余部分,没有为 start_date 和 end_date 变量留下任何内容,并且很可能是问题的根本原因。

我建议使用这个正则表达式: %[^ ] -- 它将在第一个空格处停止扫描:

sscanf(buffer, "%d %[^ ] %d-%d", &rno, name, &start_date, &end_date)

如果有 2 个名称用空格分隔,您可以这样做来解决这种情况——请记住,在此示例中,成功的 sscanf() 应返回 5:

sscanf(buffer, "%d %[^ ] %[^ ] %d-%d", &rno, fname, lname, &start_date, &end_date)

注意:@Weather Vane 非常友善地指出 %s 将代替 %[^ ]。是的,当然!(再次感谢)。

所有建议都已成功测试在具有此格式的数据文件上...显示版本 2 (名字 + 姓氏):

1 First Last 1933-1944
2 First Last 1944-1948
...
...

评论

1赞 Poizone 10/6/2023
1 总统 2004-2016 - 这是文件中包含的数据。
1赞 Weather Vane 10/6/2023
@Poizone那为什么你需要而不是名字呢?%[]%s
1赞 Poizone 10/6/2023
@Kz2023 谢谢。现在没有错误,但无法写入链表。什么也没发生。可能是节点有问题。我会试着弄清楚的。
1赞 Fe2O3 10/6/2023
@Kz2023的优先级高于......可能想纠正你的问题,因为它目前没有做你认为它正在做的事情......===if()
1赞 greg spears 10/6/2023
@Fe2O3 -- 谢谢!我很感激你。我匆匆忙忙...我知道我应该把这句话括起来。我不知道 = vs == ....再次感谢
1赞 chqrlie 10/6/2023 #2

给定输入行的格式,无法在发布的单个调用中解析它们。您应该使用 和 找到第一个和最后一个空格字符,然后用于转换数字并复制中间部分,即名称,其中可能嵌入了多个空格,例如:、。sscanfstrchr()strrchr()sscanf()strcpyTheodore RooseveltWilliam H. Taft

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

void readDataFromFile(President **h) {
    FILE *fp = fopen("President.txt", "r");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open file %s: %s\n",
                "President.txt", strerror(errno));
        return;
    }

    char buffer[MAX];
    int rno, start_date, end_date, count = 0;

    // Locating the last node if any
    while (*h != NULL) {
        h = &(*h)->next;
    }

    while (fgets(buffer, sizeof buffer, fp) != NULL) {
        char *first = strchr(buffer, ' ');
        char *last = strrchr(buffer, ' ');
        if (!first || !last
        ||  (first += strspn(first, " ")) >= last 
        ||  sscanf(buffer, "%d", &rno) != 1
        ||  sscanf(last, "%d-%d", &start_date, &end_date) != 2) {
            fprintf(stderr, "invalid format: %s\n", buffer);
            break;
        }
        while (last > buffer && last[-1] == ' ')
            last--;

        // Creating of new node
        President *newNode = calloc(sizeof(*newNode), 1);
        if (newNode == NULL) {
            fprintf(sdterr, "Memory allocation error!\n");
            break;
        }
        newNode->rno = rno;
        // copy the name: use `snprintf` to prevent buffer overflow
        snprintf(newNode->name, sizeof newNode->name,
                 "%.*s", (int)(last - first), first);
        newNode->start_date = start_date;
        newNode->end_date = end_date;
        newNode->next = NULL;

        // Appending new node to list
        *h = newNode;
        h = &(*h)->next;
        count++;
    }

    fclose(fp);
    printf("%d records added to list!\n", count);
}