Realloc Without Freeing Old Memory

How can I use realloc function without discarding the old memories

An example incorporating all improvements suggested in the comments and avoiding the use of global variables, and freeing all allocated memory before the program exits. There is only a need to hold the terminal window open on windows, so conditionally enclose the system("pause");.

Putting it altogether, you would have:

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

int *double_ptr (int *ptr, int *ptrsz) /* pass needed information as parameters */
{
int *newptr = malloc (2 * *ptrsz * sizeof *newptr); /* allocate new block of mem */

if (newptr) { /* validate allocation */
memcpy (newptr, ptr, *ptrsz * sizeof *ptr); /* copy to new block of mem */
*ptrsz *= 2; /* update allocated size */
}

return newptr; /* return pointer */
}

void print (int *ptr1, int *ptr2) /* pass needed information as parameters */
{
/* only one call to printf required */
printf ("ptr1 -> %p, *ptr1 = %d\nptr2 -> %p, *ptr2 = %d\n\n",
(void*)ptr1, *ptr1, (void*)ptr2, *ptr2);
}

int main (void) {

int *ptr1 = NULL, *ptr2 = NULL, lenPtr1 = 10; /* avoid global variables */

if (!(ptr1 = malloc (lenPtr1 * sizeof *ptr1))) { /* validate EVERY allocation */
perror ("malloc-ptr");
return 1;
}
ptr2 = ptr1; /* pointer 1 and 2 hold same address where 10 is stored in memory */
*ptr1 = 10;

printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);

if (!(ptr1 = double_ptr (ptr1, &lenPtr1))) { /* double size of ptr1 */
perror ("malloc-double-ptr1");
return 1;
}

printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);

free (ptr1); /* free allcoated memory */
free (ptr2);

#if defined (_WIN32) || defined (_WIN64)
system("pause");
#endif
}

Example Use/Output

$ ./bin/doubleptrsz
lenPtr1: 10
ptr1 -> 0xb18260, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10

lenPtr1: 20
ptr1 -> 0xb186a0, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10

Let me know if you have further questions.

realloc without freeing old memory

You should take a look at the source code of realloc() from the libc you are using. From there, it should be easy to see the path followed when it can increase the size in place, and the else case where a new pointer will be returned instead. Then, use that to code your own tryrealloc() function.

For example, this is the realloc() source code from uclibc : http://cristi.indefero.net/p/uClibc-cristi/source/tree/nptl/libc/stdlib/malloc/realloc.c

24  void *
25 realloc (void *mem, size_t new_size)
26 {
...
57 if (new_size > size)
58 /* Grow the block. */
59 {
60 size_t extra = new_size - size;
61
62 __heap_lock (&__malloc_heap_lock);
63 extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);
64 __heap_unlock (&__malloc_heap_lock);
65
66 if (extra)
67 /* Record the changed size. */
68 MALLOC_SET_SIZE (base_mem, size + extra);
69 else
70 /* Our attempts to extend MEM in place failed, just
71 allocate-and-copy. */
72 {
73 void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);
74 if (new_mem)
75 {
76 memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);
77 free (mem);
78 }
79 mem = new_mem;
80 }
81 }
...

I have removed some parts for clarity. But you can see that at line 66, it check if it can simply increase the memory for the current pointer. This is the part you want to keep. The else case starting at line 69 is to handle the case where the old memory will be freed and a new pointer will be returned. This is the part you want to kick out and handle it differently. From what you are saying, I guess you will only want to remove line 77, where it does the free.

If you go this way, remember that you will have to manually either free the old pointer or the new one, as both will now be valid (and you don't want a memory leak).

Also, this is for uclibc. If you are already using a different libc, you should base your new tryrealloc() function on the realloc() function of that libc.

EDIT: You must be careful if you use this approach. You will be basing your solution on the internals of the memory manager, so things can change and be different between the various libc implementations, but also between different versions of the same libc. So do that with the appropriate care and warning in mind.

Does realloc() free old memory (when old memory might be pointers to other memory)?

realloc() only reallocates the top-level array you give it. As EOF mentioned in a comment, it doesn't know that the contents of the array are pointers, so it can't do anything to those elements.

If you're enlarging the array, you don't need to do anything with the arrays that it points to. Their memory is untouched, and the pointers will be copied from the old memory to the new memory allocated by realloc().

If you're shrinking the array, you need to make sure that you first free any of the arrays that were pointed to by the elements that are beyond the end of the result, to avoid leaking memory.

How free memory after of realloc

I think your confusion comes from the (uninspired) expression "free pointers" (you used in your post, but edited it out since). You don't free pointers. You free memory. The pointer is just telling which memory.


In your example you have: the memory obtained from malloc. string1 points to this memory. Then when you call realloc a new memory block is obtained (possibly starting at the same address, possibly not), but realloc takes care to release the old one if needed (and is therefore undefined behavior to access or free it yourself). string2 points to this new memory block.

So you have to free just the memory block obtained from realloc. string2 points to that memory.

Using free() after realloc()


If we use realloc() to extend an array, do we need to call free() on the pointer to the old array?

No. If realloc() succeeds then realloc() will handle memory management for the old pointer you passed (this is why realloc() requires you to pass a pointer that was allocated using malloc/calloc/realloc or NULL. If NULL is passed to realloc() then it's equivalent to calling malloc() with the same requested size).

From 7.22.3.5 The realloc function:

From The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.

(emphasis mine).

You only need to free() if the call to realloc() fails. For example:

/* 'old_ptr' was allocated using malloc/realloc/calloc or it's NULL. */
char *new_ptr = realloc(old_ptr, new_size);
if (!new_ptr) {
perror("realloc");
free(old_ptr);
exit(1);
}
old_ptr = new_ptr;
...

is a common pattern of realloc() usage.

is using realloc() a good idea for deep copying arrays?

That really depends on the specific use-case. Calling realloc() too often may not desirable (for example, realloc'ing 1 byte more than the previous size can result in a lot of copying). Typically, the new size is increased using a good strategy based on the application. Doubling it every time you need to realloc() is a common strategy.

Does realloc overwrite old contents?

Don't worry about the old contents.

The correct way to use realloc is to use a specific pointer for the reallocation, test that pointer and, if everything worked out ok, change the old pointer

int *oldpointer = malloc(100);

/* ... */

int *newpointer = realloc(oldpointer, 1000);
if (newpointer == NULL) {
/* problems!!!! */
/* tell the user to stop playing DOOM and retry */
/* or free(oldpointer) and abort, or whatever */
} else {
/* everything ok */
/* `newpointer` now points to a new memory block with the contents of oldpointer */
/* `oldpointer` points to an invalid address */
oldpointer = newpointer;
/* oldpointer points to the correct address */
/* the contents at oldpointer have been copied while realloc did its thing */
/* if the new size is smaller than the old size, some data was lost */
}

/* ... */

/* don't forget to `free(oldpointer);` at some time */

C - If realloc is used is free necessary?

Neither is correct. realloc() can return a pointer to newly allocated memory or NULL on error. What you should do is check the return value:

ptr1 = realloc(ptr2, 3 * sizeof(int));
if (!ptr1) {
/* Do something here to handle the failure */
/* ptr2 is still pointing to allocated memory, so you may need to free(ptr2) here */
}

/* Success! ptr1 is now pointing to allocated memory and ptr2 was deallocated already */
free(ptr1);


Related Topics



Leave a reply



Submit