程序在重新分配时崩溃

Program crashing at realloc

问题

我目前正在为 Windows 编写一个类似 grep 的小(而且很糟糕)程序。在其中我想逐行读取文件并打印出包含密钥的文件。为此,我需要一个函数来读取文件的每一行。因为我不在 Linux 我不能使用 getline 功能,必须自己实现它。

我找到了实现此类功能的 SO 。我试过了,它适用于 'normal' 文本文件。但是如果我尝试读取一个行长度为 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 '[=10=]' 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 以确保它在那里崩溃并且确实如此。

问题

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

在这个片段中

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

you add size + BUFSIZ 并分配它,但随后您读取相同的内容 – 增加了! – size。从本质上讲,你正在阅读越来越多的字符,而不是你在每一轮分配的字符。第一次,size = BUFSIZ 并且您准确阅读了 size/BUFSIZ 个字符。如果该行长于此(最后一个字符不是 \n),则增加内存大小(size += BUFSIZ)但您 读取它的( new) total size 再次 - 你已经处理了最后的 size 字节数。

分配的内存随着每个循环 BUFSIZE 增长,但是要读取的字节数 随着 BUFSIZE 增加 – 在一个循环之后,它是 BUFSIZE,经过两次循环 2*BUFSIZE,依此类推,直到重要的内容被覆盖,程序终止。

如果您只读取 BUFSIZE 的确切大小的块,那么这应该有效。

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

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

这样您的代码就不会尝试读取输入文件末尾之后的内容。