无法在非常特殊的情况下重新分配内存

Can not reallocate memory in a very peculiar circumstance

几乎最小的可重现示例:

prog.c

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

int main(void) {
char *buffer;
int c;
size_t bufsiz = 1024, i = 0;

if (!(buffer = malloc(bufsiz))) {
    fputs("malloc() failed!\n", stderr);
    return 1;
}

while (EOF != (c = fgetc(stdin))) {
    buffer[i] = c;
    if (++i == bufsiz && !(buffer = realloc(buffer, bufsiz *= 2))) {
        fputs("realloc() failed! (loop)\n", stderr);
        return 1;
    }
}
buffer[i] = '[=10=]';

if (!(buffer = realloc(buffer, i))) {
    fputs("realloc() failed! ", stderr);
    fprintf(stderr, "%d\n", i);
    return 1;
}

fputs(buffer, stdout);
return 0;
}

我用这个命令编译和 运行:

gcc prog.c -o prog

此命令按预期将 prog.c 的内容复制到 exp

cat prog.c | ./prog > exp

此命令打印错误消息“realloc() 失败! 0”:

cat prog.c | ./prog > prog.c

我还没有找出这种奇怪行为背后的原因...

P.S.: 我正在使用 GNU cat 和 bash

恭喜,您(重新)发现了系统实现 realloc 中的一个错误,其中将“成功”大小调整为 0 与错误没有区别。按照规定,如果 realloc returns 一个空指针,它已经失败并且旧对象仍然存在。但一些历史实现将 realloc(p,0) 视为 free(p)。 C 标准的未来版本允许这种行为,并反对使用零大小的 realloc,所以如果你想像这样使用 realloc,你应该确保你没有传递零大小.

正如 Eric Postpischil 在评论中指出的那样:

Where does your program put a null character at the end of the string in the buffer?

您的缓冲区的可能大小为 0 的事实表明存在问题 - 您忘记保留 space 来终止字符串 - 如果您修复此问题,即使是 zero-length 字符串采用非零字节数。

cat prog.c | ./prog > prog.c 中,shell 解析命令,发现有一个重定向到 prog.c,并打开 prog.c 进行写入,这将删除之前的任何内容文件。然后 cat prog.c 看到一个空文件并将其复制到标准输出。 ./prog 忠实地再现了这个空流。