繁体   English   中英

多个fscanf

[英]Multiple fscanf

我已经编写了以下程序,旨在将文件中的字符串读取到变量“ title”中:

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

int main()
{
    int m, b;
    char *title;
    FILE *fp;

    fp = fopen("input2.txt", "r");
    if (fp == NULL)
    {
         printf ("Error: file cannot be found\n");
         return 1;
    }

    fscanf(fp, "<%d>\n<%d>", &m, &b);
    printf("%d\n%d", m, b);
    fscanf(fp, "<%s>", title);

    fclose(fp);
    return 0;
}

上面的程序在第二次调用fscanf崩溃。 为什么会这样?

您的主要问题是您尚未为读取的字符串分配空间。 您可以通过多种方式执行此操作:

char title[256];

要么:

char *title = malloc(256);
if (title == NULL)
{
    fprintf(stderr, "Out of memory\n");
    exit(1);
}

然后应将其中任何一个与:

if (fscanf(fp, " <%255[^>]>", title) != 1)
{
    fprintf(stderr, "Oops: format error\n");
    exit(1);
}

或者,如果您的系统具有与POSIX 2008兼容的fscanf()实现,则可以将m修饰符用于%s (或使用%c ,在这种情况下,还可以使用扫描集%[...] —下面的更多内容):

char *title = 0;

if (fscanf(fp, " <%m[^>]>", &title) != 1)  // Note the crucial &
{
    fprintf(stderr, "Oops: format error\n");
    exit(1);
}

这样,如果fscanf()整体成功,函数将为标题分配内存。 如果失败,则内存将被释放(或从未分配)。

请注意,我将%s更改为%m[^>] 这是必要的,因为原始转换永远不会与>匹配。 如果输入中有一个> ,它将被合并到结果字符串中,因为它最多读取空格,而>不是空格。 此外,您将无法判断尾随上下文是否曾经匹配过-这是原始格式中的> ,在我建议的修订代码中,这还是一个问题(是否存在)。

我还在字符串的开头添加了一个空格,以匹配可选的空白。 否则,假设根本没有> ,则字符串开头的<必须与第二个数字之后的>位于同一行。 您还应该检查第一个fscanf()的返回值:

if (fscanf(fp, "<%d>\n<%d>", &m, &b) != 2)
{
    fprintf(stderr, "Oops: format error\n");
    exit(1);
}

请注意,嵌入的换行符只是在><之间寻找空格,即零个或多个空格,制表符或换行符。 还要注意,您将永远不会知道第二个>是否匹配。

您可以使用exit(EXIT_FAILURE); 代替exit(1); —或者,因为此代码在main() ,所以您可以使用return 1; return(EXIT_FAILURE); 括号在两种情况下都是可选的,但在某些情况下它们的出现会引起不必要的怒火。

您还可以改善错误消息。 而且,您应该考虑使用fgets()或POSIX的getline()然后使用sscanf()因为(到目前为止)这样做可以更轻松地进行良好的错误报告,而且,如果首次尝试转换数据失败,则可以轻松地重新扫描数据。

这个:

    char *title;

只是一个字符的指针。 如果fscanf向其中写入了多个字符,则在运行完之后,您将破坏存储器中的任何内容

您需要执行以下两项操作之一:

    char title[50]; // Holds up to 49 characters, plus termination

要么:

    #include <stdlib.h>
    // ...
    char *title = malloc(50 * sizeof(char)); // Same capacity as above
    if (title == NULL) {
        // handle out of mem error
    }
    // ...
    free (title);

第一个选项显然要简单得多,但是需要您在编译时知道数组大小。

如果您不熟悉编程,还没有遇到指针和动态内存分配,请暂时坚持使用第一个选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM