我们在realloc缓冲区后会丢失数据吗?

40

我对realloc的工作原理感到困惑。如果我使用malloc分配了一块缓冲区,并将数据复制到该缓冲区,比如说"AB":

 +------------+
 | A | B | \0 |
 +------------+

我使用realloc重新分配了缓冲区,是否会导致数据丢失(即使只有一个字节)?或者它只是扩展了缓冲区?

 +------------------------+
 | A | B | \0 | ? | ? | ? |
 +------------------------+

代码:

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

int main(void){

    char* buffer    = (char*) malloc( sizeof(char) * 3 );
    strncpy(buffer, "AB", 2);

    buffer          = (char*) realloc(buffer, sizeof(char) * 6); /* Will there be any lost here? */
    free(buffer);
    return(0);
}
2个回答

69

使用realloc增加内存块的大小会保留原始内存块的内容。即使无法就地调整内存块的大小,旧数据也将复制到新块中。如果realloc缩小内存块的大小,则旧数据将被截断。

请注意,如果realloc失败,则您的数据将会丢失。这是因为realloc通过返回NULL来表示失败,但在这种情况下,原始的内存块仍然有效,但您无法访问它,因为您已经用NULL覆盖了指针。

标准模式如下:

newbuffer = realloc(buffer, newsize);
if (newbuffer == NULL)
{
    //handle error
    return ...
}
buffer = newbuffer;

需要注意的是,在 C 语言中,将 malloc 的返回值进行强制类型转换是不必要的,并且按照定义,sizeof(char) 等于 1


1
为什么不能使用 buffer = realloc(buffer, newsize); - ylun.ca
3
@ylun,根据答案中所述的原因。 - David Heffernan
为了防止数据丢失,您首先要检查分配是否成功,然后重新分配。谢谢。 - ylun.ca
1
如果你重新分配一个较小的内存块会发生什么? - Kenny Worden
显然,您会失去您释放的内容,但是您会保留其余部分。 - David Heffernan

5

没有丢失任何东西。但是你确实应该测试一下realloc()(以及之前的malloc())是否“有效”。
另外,将返回值强制转换为malloc的返回类型,最多是多余的,而且它可能会隐藏一个编译器在其缺失时会捕获的错误。

基于你想要字符串的假设,你对strncpy的使用是错误的

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

int main(void) {
    char *buffer = malloc(3);
    if (buffer == NULL) /* no memory */ exit(EXIT_FAILURE);

    strncpy(buffer, "AB", 2);
    /* ATTENTTION! ATTENTION: your array is not a string.
    ** buffer[2] is not the zero string terminator */

    // buffer = realloc(buffer, 6); /* Will there be any lost here? */
    /* If realloc returns NULL, you've just lost the only pointer to
    ** the allocalted memory, by overwriting it with NULL.
    ** Always `realloc` to a temporary variable */
    char *tmp_buffer = realloc(buffer, 6);
    if (tmp_buffer == NULL) {
        /* realloc failed */
    } else {
        /* realloc worked, no bytes lost */
        buffer = tmp_buffer;
        /* ATTENTION! ATTENTION: buffer is still not a string
        ** buffer[0] is 'A', buffer[1] is 'B',
        ** all other elements of buffer are indeterminate */
    }

    free(buffer);
    return(0);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接