#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 1024
void reverse(FILE *, FILE *);
int main(int argc, char ** argv)
{
...
reverse(fptr, stdout);
...
return 0;
}
void reverse(FILE * instream, FILE * outstream)
{
char ** buf;
char * lbuf;
int counter, i;
size_t slen;
counter = 0;
buf = malloc(MAXLEN * sizeof(char));
if (buf == NULL)
{
fputs("malloc failed\n", stderr);
exit(EXIT_FAILURE);
}
lbuf = NULL;
while ((counter < MAXLEN) && (getline(&lbuf, &slen, instream) != -1))
{
buf[counter] = lbuf;
counter++;
lbuf = NULL;
}
for (i = counter - 1; i >= 0; i--)
{
fputs(buf[i], outstream);
free(buf[i]);
}
free(buf);
}
我编写了这个函数来以相反的顺序打印文件,例如
Hello World
How are you ?
what are you doing ?
输出应该是这样的
what are you doing ?
How are you ?
Hello World
但出现了意想不到的行为。我正在使用 Linux 特定stdio
功能getline()
来扫描任意长行。问题是,如果 的值为MAXLEN
4, 5, 6, ... 这样,程序在打印输出时会给出double free or corrupt address error abort()
特定的功能。free()
我查看了该函数返回的地址,geline()
似乎在 4 次迭代之后,该函数返回的第一个缓冲区的地址getline()
已损坏。如果MAXLEN
是 2 或足够大(例如 1024),则不会出现问题。
输入样本我拿的
When to the sessions of sweet silent thought
I summon up remembrance of things past,
I sigh the lack of many a thing I sought,
And with old woes new wail my dear time's waste:
Then can I drown an eye, unused to flow,
For precious friends hid in death's dateless night
And weep afresh love's long since cancell's woe,
答案1
在 中char ** buf;
, 的类型buf
是pointer to char*
,您在其中为 的数组分配空间char*
。
buf = malloc(MAXLEN * sizeof(char));
这仅为 MAXLEN 字符分配空间,而不为 MAXLEN 指针分配空间(每个指针在 64 位 CPU 上为 8 个字节)。因此,您稍后会超出分配的空间,并且条目会损坏(它们与 重叠buf[counter]
)。
正确的分配是:buf = malloc (MAXLEN * sizeof(char *));
通常我更愿意根据返回的指针的类型进行分配:
buf = malloc (MAXLEN * sizeof(*buf));
即“为事物buf
指向的 MAXLEN 项分配空间”。这可以避免buf
更改类型时引入的错误。
getline()
不是问题的一部分:您只需将它返回的指针存储在一个对它们来说太小的数组中。您的代码适用于小数据集的原因是,将malloc()
分配四舍五入到 16 或 32 字节以保持对象的对齐(两者都是针对其自己的空闲列表,因此编译器可以对用户结构的对齐做出合理的假设)。
因此(通常)您的前两行数据正常,接下来的两行会损坏下一行的隐藏标题(破坏free()
),之后的行会损坏您的文本数据。