多个fscanf

Elo*_*din 1 c arrays pointers scanf buffer-overflow

我编写了以下程序,用于将文件中的字符串读入变量"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;
}
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*ler 5

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

char title[256];
Run Code Online (Sandbox Code Playgroud)

要么:

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

其中任何一个都应该用于:

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

或者,如果您的系统具有fscanf()与POSIX 2008兼容的实现,您可以使用m修饰符%s(或者使用%c,或者,在本例中为扫描集%[...]- 更多内容如下):

char *title = 0;

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

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

请注意,我换%s%m[^>].这是必要的,因为原始转换永远不会匹配>.如果>输入中有a ,它将被合并到结果字符串中,因为它读取到空白区域,而>不是空白区域.此外,您将无法判断尾随上下文是否曾匹配 - 这是>原始格式,并且在我建议的修订代码中仍然存在问题(或不存在).

我还在字符串的开头添加了一个空格来匹配可选的空格.没有它,<字符串开头必须>与第二个数字后面的行相同,假设它>完全存在.你还应该检查第一个回报fscanf():

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

请注意,嵌入式换行只是查找>和之间的<空白 - 即零或多个空格,制表符或换行符.另请注意,您永远不会知道第二个>是否匹配.

你可以使用exit(EXIT_FAILURE);代替exit(1);-或者,因为这代码是main(),你可以使用两种return 1;return(EXIT_FAILURE);其中括号是在两种情况下可选的,但它们的存在唤起某些人无端的愤怒.

您还可以改进错误消息.您应该考虑使用fgets()getline()后面使用POSIX ,sscanf()因为它可以更容易(到目前为止)进行良好的错误报告,而且如果第一次尝试转换数据失败,您可以轻松地重新扫描数据.