【问题标题】:Program crashing at realloc程序在 realloc 崩溃
【发布时间】:2018-12-22 07:31:57
【问题描述】:

问题

我目前正在为 Windows 编写一个类似于 grep 的小型(和糟糕的)程序。在其中我想逐行读取文件并打印出包含密钥的文件。为此,我需要一个读取文件每一行的函数。由于我不在 Linux 上,我无法使用 getline 函数,必须自己实现。

我找到了一个 SO answer 实现了这样的功能。我试过了,它适用于“普通”文本文件。但是,如果我尝试读取行长为 13 000 个字符的文件,程序就会崩溃。

MCVE

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

char * getline(FILE *f)
{
    size_t size = 0;
    size_t len  = 0;
    size_t last = 0;
    char *buf = NULL;

    do {
        size += BUFSIZ; /* BUFSIZ is defined as "the optimal read size for this platform" */
        buf = realloc(buf, size); /* realloc(NULL,n) is the same as malloc(n) */            
        /* Actually do the read. Note that fgets puts a terminal '\0' on the
           end of the string, so we make sure we overwrite this */
        if (buf == NULL) return NULL;
        fgets(buf + last, size, f);
        len = strlen(buf);
        last = len - 1;
    } while (!feof(f) && buf[last] != '\n');
    return buf;
}

int main(int argc, char *argv[])
{
    FILE *file = fopen(argv[1], "r");
    if (file == NULL)
        return 1;

    while (!feof(file))
    {
        char *line = getline(file);
        if (line != NULL)
        {
            printf("%s", line);
            free(line);
        }
    }
    return 0;
}

这是我正在使用的file。它包含三行可以很好阅读的短行和我的一个 Qt 项目中的长行。读取此行时,getline 函数将 2 次重新分配到 1024 的大小,并在第 3 次崩溃。我在realloc 周围加上了printf,以确保它在那里崩溃并且确实如此。

问题

谁能解释一下为什么我的程序会这样崩溃?我只是花几个小时在这上面,不知道该怎么办了。

【问题讨论】:

  • add size + BUFSIZ 并分配它,但随后你 读取 一样 - 增加了! –size。从本质上讲,您阅读的字符数比您在每一回合中分配的字符数越来越多。如果您只阅读BUFSIZE,那么这应该可以。
  • 你不检查fgets()是否失败...
  • @usr2564301 谢谢!我可以发誓我已经尝试过这个,因为它对我来说也没有多大意义。随时发布答案,我会接受。干杯。
  • 关于:buf = realloc(buf, size); 调用realloc() 时,始终将返回值保存到“temp”变量中,检查“temp”变量,只有在不为NULL 时才复制到目标变量。否则,当realloc()失败时,分配内存的指针丢失,导致内存泄漏是结果

标签: c file line realloc


【解决方案1】:

在这个片段中

    size += BUFSIZ;
    buf = realloc(buf, size);
    if (buf == NULL) return NULL;
    fgets(buf + last, size, f);

add size + BUFSIZ 并分配它,但你读到的却是一样的——增加了! –size。从本质上讲,您阅读的字符数比您在每一回合中分配的字符数越来越多。第一次,size = BUFSIZ,而您准确地读取了size/BUFSIZ 字符。如果该行比这个长(最后一个字符不是\n),你增加内存的大小(size += BUFSIZ)但是你读取它的(新的)total 再次调整大小 - 您已经处理了最后一个 size 字节数。

每个循环分配的内存随着BUFSIZE 的增加而增长,但是要读取的字节量随着BUFSIZE 而增加 – 一个循环之后是BUFSIZE,两个循环之后是2*BUFSIZE,以此类推,直到某些重要内容被覆盖并终止程序。

如果您只读取精确大小为 BUFSIZE 的块,那么这应该可以工作。

请注意,您的代码希望最后一行以\n 结尾,这可能并不总是正确的。您可以通过额外的测试来捕捉到这一点:

if (!fgets(buf + last, size, f))
    break;

因此您的代码不会尝试读取输入文件的末尾。

【讨论】:

    猜你喜欢
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 2013-08-23
    • 2017-03-26
    相关资源
    最近更新 更多