程序在重新分配时崩溃
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;
这样您的代码就不会尝试读取输入文件末尾之后的内容。
问题
我目前正在为 Windows 编写一个类似 grep 的小(而且很糟糕)程序。在其中我想逐行读取文件并打印出包含密钥的文件。为此,我需要一个函数来读取文件的每一行。因为我不在 Linux 我不能使用 getline
功能,必须自己实现它。
我找到了实现此类功能的 SO
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;
这样您的代码就不会尝试读取输入文件末尾之后的内容。