程序在重新分配时崩溃

时间:2018-07-13 21:49:42

标签: c file line realloc

问题

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

我已经找到了实现此类功能的SO answer。我尝试了一下,它对于“普通”文本文件也能正常工作。但是,如果我尝试读取行长为13000个字符的文件,程序就会崩溃。

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次崩溃。我将printf放在realloc周围,以确保它在那里崩溃并且确实可以。

问题

有人可以解释我为什么我的程序崩溃吗?我只是花了几个小时而已,不知道该怎么办。

1 个答案:

答案 0 :(得分:2)

在此片段中

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

添加 size + BUFSIZ并进行分配,但随后您读到的内容却一样-增加了! – size。从本质上讲,您阅读的字符比每次分配的字符要多。初次使用size = BUFSIZ时,您会准确地读取size / BUFSIZ个字符。如果行长于此(最后一个字符不是\n),则增加内存的大小(size += BUFSIZ),但您读取其(新)< em>总计大小–您已经处理了最后size个字节。

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

如果您仅读取大小为BUFSIZE的块,则应该可以。

请注意,您的代码希望最后一行以\n结尾,但不一定总是如此。您可以通过其他测试来了解这一点:

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

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