realloc会对旧指针做什么

时间:2016-04-28 19:03:29

标签: c pointers realloc

我对realloc函数有疑问。应用realloc函数后,是否会更改旧指针的内容? 代码是

main () {
    int *a, *b, i;

    a = calloc(5, sizeof(int));
    for (i = 0; i < 5; i++)
            a[i] = 1;
    for (i = 0; i < 5; i++)
            printf("%d", a[i]);
    printf("\n%p\n", a);

    b = realloc(a, 200000 * sizeof(int));
    if(b == NULL)
            printf("error\n");
    for (i = 0; i < 5; i++)
            printf("%d", a[i]);
    printf("\n");
    for (i = 0; i < 10; i++)
            printf("%d", b[i]);

    printf("\n%p %p\n", a, b);
}

输出

11111
0x2558010
00111
1111100000
0x2558010 0x7f29627e6010

指针仍指向同一地址,但内容已更改。

6 个答案:

答案 0 :(得分:6)

  

指针仍指向同一地址,但内容已更改。

这是因为realloc()可能会首先尝试增加a指向的块的大小。但是,它可以改为分配一个新块,将数据(或尽可能多的数据)复制到新块,并释放旧块。在调用a之后,您确实不应该使用b = realloc(a, 200000 * sizeof(int)),因为realloc调用可能会将块移动到新位置,而a指向不再分配的内存。请改用b

答案 1 :(得分:4)

realloc返回的值告诉您它是成功还是失败。

b = realloc(a, 200000 * sizeof(int));

如果失败,则返回空指针,a仍然指向原始未修改的内存块(当然b是空指针)。

如果成功,则b指向(可能是新分配的)内存块,a的值为不确定。如果它能够将旧块分配到与旧块相同的位置(通过增加或缩小块),那么b将等于a - 但是测试它,或者即使是指a的值,也有未定义的行为。如果必须重新定位块,则realloc在复制数据后将完成相当于free(a)的操作。在任何一种情况下,最好将a设置为NULL,以避免意外引用其(现在不确定)值。

请注意,即使新大小较小,realloc也可以重新定位块。

答案 2 :(得分:0)

阅读手册页是关键,但TLDR是如果没有足够的内存在前一个块的后端放大,它将获得一个新的内存块,将旧数据复制到其中,以及返回新块的地址。不应使用旧地址,最典型的realloc语句如下所示

   a = realloc(a, 200000 * sizeof(int));

这样你就不会意外地使用可能错误的旧值。

它无法更改指针中的地址,因为它是按值传递的,因此在函数中更改它只会更改本地副本。

编辑:每个风向标的绝对正确评论,更安全的路线将是

   void * b = realloc(a, 200000 * sizeof(int));
   if ( b ) {
       a = b;
   } else {
       ;;; /* error handler here */
   }

答案 3 :(得分:0)

简单的realloc实施应该回答您的问题:

void * realloc(void * ptr, size_t desired_size) {
    size_t allocated_size = _allocated_size_of(ptr);
    if (allocated_size < desired_size) {
        void * new_ptr = malloc(desired_size);
        memcpy(new_ptr, ptr, allocated_size);
        free(ptr);
        ptr = new_ptr;
    }
    return ptr;
}

malloc及相关功能并不总是精确分配所需的尺寸。他们经常分配超过所需的大小。存储器分配函数保留了一些隐藏数据,这允许由malloc或相关函数分配的指针用于查找已分配的存储器块大小。如何理解这一点并不是必须的,但是一些非常简单的实现只是在指针返回*(((size_t)ptr)-1)之前的空间中存储大小。

答案 4 :(得分:0)

如果realloc()返回的指针与您传入的指针不同(大部分时间都是这样),那么您传入的指针不再属于您,并且您没有业务知道或关心什么成为它。它可能会改变它的内容,也可能不会。但是你不再被允许访问它,所以你可以不关心它。

答案 5 :(得分:0)

如果&#39; a&#39;指向一个有效的内存块(来自之前的malloc / realloc / calloc),然后重新分配调用将尝试使用您请求的新大小提供一块内存 realloc调用的格式应为*tmp = realloc (a ...

必须测试realloc的返回值 如果它为NULL,则realloc无法分配所请求的内存,这就会导致&#39; a&#39;作为有效指针
然后,您负责处理&#39; a&#39;指向的任何数据。 (保存/丢弃它)你负责free&#39; a&#39;指向的内存。

如果realloc调用成功,请创建b = tmp,现在&#39; b&#39;是指向内存块的新指针 - 起始位置是否与&#39; a&#39;相同无关紧要。或者不同。 &#39;一个&#39;不再是一个有效的内存分配指针,虽然进一步的错误将取决于是否&#39; a&#39;指向您的程序所拥有的内存 - 基本上如果a == b,&#39; a&#39;可以在没有明显错误的情况下访问。

有效*tmp = realloc(a ...&amp; b = tmp;
1)如果重新分配的存储器的起始位置不变:(a == b)
它将分配所请求的内存
但是在valgrind下运行它会看到错误消息:
无效的free()/ delete / delete [] / realloc()
无效 地址0x51fc040是大小为256的块内的0字节空闲&n; d 在这种情况下,realloc无法释放&#39; a&#39;
指向的内存 再次在这种情况下&#39; a&#39;仍然可以访问,因为它是指向分配给你的程序的内存的指针

2)如果重新分配的内存的起始位置发生了变化:(a!= b)
它会失败,Valgrind会显示如下输出:
地址:0x1e89010
地址b:0x7f2c5893c010
a realloc:0x1e89010
`./test15' ;:realloc()出错:旧的大小无效:0x0000000001e89010

并试图访问&#39; a&#39;将失败 - 甚至试图打印它作为指针失败的值,大概是因为它不再指向程序拥有的内存

换句话说,使用&#39; a&#39;在b = realloc(a ...之后是未定义的行为 以上评论基于使用以下代码:

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

int main(void)
{
    int *a = NULL, *b = NULL, *c = NULL;

    /* initial allocation */
    a = malloc(256);
    if( a == NULL) return (1);
    printf("address of a: %p\n", a);

    /* reallocation 'b' MAY be same as 'a' - try much larger allocations */
    void *tmp = realloc(a, 512);
    if ( !tmp ) {
        free(a);
        return (1);
    } else {
        b = tmp;
    }
    printf("address of b: %p\n", b);

    /* see what 'a' is now - this MAY crash the program*/
    printf("a after realloc: %p\n", a);

    /* 'a' may not be a valid pointer - try using it for another realloc */
    c = realloc(a, 256);
    /* Valgrind shows that memory could not be free'd or 'a' was not valid allocated memory */
    printf("return value of c: %p\n", c);
    if (c != NULL) {
        free(c);
        printf("'c' allocated\n");
    } else {
        free(b);
        printf("'c' not allocated\n");
    }

    return 0;
}