what will realloc do to the old pointer [duplicate]

不问归期 提交于 2020-08-23 04:56:50

问题


I have a question about the realloc function. Will the content of old pointer be changed after apply realloc function? The code is

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);
}

The output is

11111
0x2558010
00111
1111100000
0x2558010 0x7f29627e6010

Pointer a still point to the same address, but the content is changed.


回答1:


Pointer a still point to the same address, but the content is changed.

That's because realloc() may first try to increase the size of the block that a points to. However, it can instead allocate a new block, copy the data (or as much of the data as will fit) to the new block, and free the old block. You really shouldn't use a after calling b = realloc(a, 200000 * sizeof(int)) since the realloc call may move the block to a new location, leaving a pointing to memory that is no longer allocated. Use b instead.




回答2:


The value returned by realloc tells you whether it succeeded or failed.

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

If it fails, it returns a null pointer, and a still points to the original unmodified chunk of memory (and of course b is a null pointer).

If it succeeds, then b points to a (possibly newly allocated) chunk of memory, and the value of a is indeterminate. If it was able to allocate the new chunk in the same place as the old one (by growing or shrinking the chunk in place), then b will be equal to a -- but testing that, or even referring to the value of a, has undefined behavior. If it has to relocate the chunk, then realloc will have done the equivalent of free(a) after copying the data. In either case, it's probably best to set a to NULL to avoid accidentally referring to its (now indeterminate) value.

Note that realloc can relocate chunk even if the new size is smaller.




回答3:


A simple realloc implementation should answer your questions:

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 and related functions don't always allocate exactly the desired size. Very often they allocate more than the desired size. There is some hidden data kept up with by the memory allocation functions which allows for a pointer that was allocated by malloc or related functions to be used to look up the memory block size that was allocated. How this is kept up with isn't necessary to understand, but some very simple implementations simply store the size in the space just before the pointer returned *(((size_t)ptr)-1).




回答4:


If realloc() returns a pointer different from the one you passed in (as it will most of the time), then the pointer you passed in no longer belongs to you, and you have no business knowing or caring what becomes of it. It might change its contents, it might not. But you are no longer allowed to access it, so it can be no concern of yours.




回答5:


If 'a' points a valid block of memory (from a previous malloc/realloc/calloc), then a realloc call will attempt to provide a block of memory with the new size you requested
The realloc call should be of the form *tmp = realloc (a ...

The return value from realloc must be tested
If it is NULL, realloc was unable to allocate the requested memory, and this leaves 'a' as a valid pointer
You are then responsible for handling any data pointed to by 'a' (save it / discard it) and you are responsible for free ing the memory pointed to by 'a'

If the realloc call was successful make b = tmp and now 'b' is the new pointer to the block of memory - it does not matter whether the start location is the same as 'a' or different. 'a' is no longer a valid memory allocation pointer, although further errors will depend on whether 'a' points to memory owned by your program or not - basically if a == b, 'a' can be accessed without obvious errors.

After a valid *tmp = realloc(a ... & b = tmp;:
1) If the start location of the reallocated memory was unchanged: (a == b)
it will allocate the requested memory
but run it under valgrind and you will see error messages:
Invalid free() / delete / delete[] / realloc()
Address 0x51fc040 is 0 bytes inside a block of size 256 free'd
In this case realloc could not free the memory pointed to by 'a'
and again in this case 'a' can still be accessed as it is a pointer to memory that is allocated to your progam

2) If the start location of the reallocated memory was changed: (a != b)
it will fail and Valgrind shows output like this:
address of a: 0x1e89010
address of b: 0x7f2c5893c010
a after realloc: 0x1e89010
Error in `./test15': realloc(): invalid old size: 0x0000000001e89010

and trying to access 'a' will fail - even trying to print it's value as a pointer fails, presumably because it no longer points to memory owned by the program

In other words, using 'a' after b = realloc(a ... is undefined behaviour.
The above commentary was based on using the following code:

#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;
}



回答6:


Reading the man page is key here, but the TLDR is if there isn't enough memory to enlarge at the back end of the previous block, it will get a new block of memory, copy the old data into it, and return the address of the new block. The old address should not be used, and most typical realloc statement looks like this

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

That way you won't accidentally use the possibly wrong old value.

It can't change the address in the pointer, since it is passed by value, so changing it in the function is only changing the local copy.

EDIT : Per Weather Vane's absolutely correct comment, the safer route would be

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


来源:https://stackoverflow.com/questions/36923389/what-will-realloc-do-to-the-old-pointer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!