C - If realloc is used is free necessary? - c

When using realloc is the memory automatically freed? Or is it necessary to use free with realloc? Which of the following is correct?
//Situation A
ptr1 = realloc(ptr1, 3 * sizeof(int));
//Situation B
ptr1 = realloc(ptr2, 3 * sizeof(int));
free(ptr1);
ptr1 = ptr2;

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

After ptr1 = realloc(ptr2, 3 * sizeof(int)); ptr2 is invalid and should not be used. You need to free ptr1 only. In some cases the return value of realloc will be the same value you passed in though.
You can safely consider ptr1=realloc(ptr2, ... as equivalent to this:
ptr1 = malloc(...);
memcpy(ptr1, ptr2, ...);
free(ptr2);
This is what happens in most cases, unless the new size still fits in the old memory block - then realloc could return the original memory block.
As other allocation functions, realloc returns NULL if it fails - you may want to check for that.

realloc() automatically frees the original memory, or returns it unchanged (aside from metadata) if you realloc() to a smaller size or there is unallocated memory available to simply expand the original allocation in place.

According to http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/, realloc returns the new memory block if the reallocation is successful, keeps the original memory block if not. Standard usage would look like this:
ptr2 = realloc(ptr1, new_size);
if (ptr2 == NULL) {
//ptr1 still contains pointer to original array
} else {
//ptr2 contains new array, ptr1 is invalid
}

In both situations, ptr1 must be freed.
Situation B is more complex because ptr2 potentially points to freed space. Or not. It depends on whether it could be reallocated. ptr2 should not be used after the realloc in B.

Related

Is there any difference between allocating realloc() to a different pointer and allocating realloc() to the same one?

I´m kind of new to using dynamic memory in C and I was wondering if there was any diference between using realloc() to allocate to a different pointer and using realloc() to allocate the same pointer.
For example:
int *ptr = calloc(10,sizeof(int))
ptr=(int*)realloc(ptr,20);
and
*ptr3;
int *ptr = calloc(10,sizeof(int))
ptr3=(int*)realloc(ptr,20);
I´ve already executed both codes and I see no real diference between both codes (nor between the values of the opinters nor the memory allocations).
Thank you.
The difference occurs in the former case when realloc fails; in that case, it returns NULL, but doesn't free the original ptr you passed it. By directly reassigning ptr, you guarantee a memory leak when realloc fails, because you no longer have the original pointer to free.
The canonical/correct usage seen here uses two pointers, one persistent, one as a temporary. The result of realloc is always put in the temporary so it can be checked (and the persistent pointer free on failure). After reallocation is known to have succeeded, the temporary pointer replaces the persistent (which is guaranteed to either be the same as the temporary, or if the allocation could not be done in place, invalid).
For the first case, if realloc fails it returns a null pointer.
You would then be assigning that null pointer to ptr making it impossible to free the memory that was originally pointed to by ptr.
Instead, do something like below:
int* p = malloc( 10 * sizeof( int ) );
/* Take note of the memory size I'm requesting in the
realloc call compared to yours. */
int* tmp = NULL;
if ( ( tmp = realloc( p, 20 * sizeof( int ) ) ) == NULL ) {
/* We failed to find available memory, but we're
still on the hook for freeing the memory pointed to by p. */
free( p );
return;
}
/* We were successful in either extending the memory pointed to by p
or a new block of memory was allocated for us and the memory pointed to by p
was copied over for us. In either case, you do not have to free p
before assigning tmp to p. */
p = tmp;

memory leak in malloc?

I've got the following faulty piece of code in C and I am wondering if there will be a memory leak or if there will be a pointer which is pointing to a free memory location.
int* p = (int*) malloc(sizeof(int));
p = NULL;
free(p);
Yes it will leak memory. You assign p to NULL before freeing the contents it's pointing to. One quick change will fix it:
int* p = malloc(sizeof(int));
free(p);
p = NULL;
The difference here is we give free the address allocated by malloc before setting p to NULL. In general setting a pointer to NULL will not free the contents, but will allow you to check if the pointer is valid or not which can have a lot of practical applications.
You will have a memory leak.
After you assign NULL to p, you no longer have a way to refer to the memory you allocated with malloc.
Your call to free will try to free NULL, doing nothing.
The following will correctly free the memory:
int *p = malloc(sizeof(int));
free(p);
p = NULL;
Note that you don't need to set p to NULL after freeing, you only really need the first two lines.

Can I still call free() on a variable that had a second malloc() call on it?

I was wondering if a malloc() call is tied to its initial variable that you assign malloc() to at all, when it comes to how the system frees the memory.
For example, can I do the following:
void * ptr1 = malloc(50);
void * ptr2 = ptr1;
ptr1 = malloc(25);
free(ptr2);
I was intending to free the memory that was initially assigned to ptr1, but later free it by another pointer.
Let's walk through this step-by-step (UNDEF means that we don't know what a value is; valid means a pointer is safe to use):
void *ptr1, *ptr2; /* ptr1=UNDEF (invalid), ptr2=UNDEF (invalid) */
ptr1 = malloc(50); /* ptr1=0xAAA (valid), ptr2=UNDEF (invalid) */
ptr2 = ptr1; /* ptr1=0xAAA (valid), ptr2=0xAAA (valid) */
ptr1 = malloc(25); /* ptr1=0xBBB (valid), ptr2=0xAAA (valid) */
free(ptr2); /* ptr1=0xBBB (valid), ptr2=UNDEF (invalid) */
free() doesn't know which if any variable the pointer it's passed is stored in; it isn't guaranteed to (but also isn't guaranteed not to) update or interact with the variables in any way. All that effectively changes from an application developer's perspective is whether it's safe to actually use that pointer, or any other references into the block of memory allocated during the malloc() call that returned it.
As mentioned by #M.M in comments, the C language specification is explicit that the value of a pointer to a deallocated object is undefined, and the compiler is permitted to modify it in any way; see Why does MISRA C state that a copy of pointers can cause a memory exception? for further discussion.
Short answer: Yes
Longer answer:
You are not calling free "on the variable", but on the value stored in the variable.
To better understand what is going on, it may be better to think of memory as a big array of bytes, and visualizing a pointer as a numeric index into that array. And on most architectures you are likely to encounter, this is actually what is going on behind the scenes.
When you do
void * ptr1 = malloc(50);
malloc is reserving a block of 50 bytes and returning a pointer to that block. That pointer is nothing more than a numeric index telling us where in memory the reserved block starts.
In theory we could (on some architectures) write
int ptr1 = (int)malloc(50);
The reasons we are not doing it, are:
sizeof(int) may not be large enough to hold a pointer
void * tells the compiler that the numeric value stored in ptr1 should be treated as a memory address.
If we continue looking at your code:
void * ptr2 = ptr1;
There is nothing magical happening here. The "numeric value" stored in ptr1 is copied into ptr2, just as if ptr1 and ptr2 were normal integer variables.
ptr1 = malloc(25);
Here you overwrite the content of ptr1 with a new "numeric value", but the old value
still exist as a copy in ptr2.
free(ptr2);
Here you call free with the value stored in ptr2. This is the value returned by malloc(50). free does not care which variable is holding that value/address. It only cares that the value/address points to the first byte of a block of memory that was reserved with malloc.
In theory, if you knew that malloc(50) returned the value 0xb00b1e5 you could do
free((void *) 0xb00b1e5);
But you can't safely predict what malloc is going to return, so don't do that.

Reassigning to a pointer variable after freeing it [duplicate]

This question already has answers here:
Reusing freed pointers in C
(4 answers)
Closed 5 years ago.
Is this legal to do? Can you assign ptr to something after it has been freed?
int * ptr = (int*) malloc(sizeof(int));
free(ptr);
ptr = (int *) malloc(sizeof(int));
You aren't reassigning the pointer after freeing it, you're just reusing the ptr variable. This is perfectly fine.
First of all, as I mentioned in the comments, please see this discussion on why not to cast the return value of malloc() and family in C..
That said, yes, the (re)-assignment is fine here.
Actually, the question wording
Can you assign ptr to something after it has been freed?
should read
Can you assign ptr with something after it has been freed?
Guess what, the assignment without free-ing is also legal as per C, but it will create a memory leak as a side effect as the variable ptr was holding the return value of a memory allocator function and you need to free the memory once you're done using it. If, you re-assign the pointer without keeping a copy of the pointer, you'll lose the access to the memory allocated by allocator function and will have no ways to free() it.
In case the pointer was holding an address of statically allocated variable, you don't get to (nned to) free it and direct re-assignment is perfectly fine. think of this below snippet.
int x = 5, y = 10;
int * p = &x;
//do something with p
p = &y; //this is fine, just a re-assignment.
Yes. it is a valid in C language.
Related stack overflow question for more information: Reusing freed pointers in C
According to cwe.mitre.org:
In this scenario, the memory in question is allocated to another
pointer validly at some point after it has been freed. The original
pointer to the freed memory is used again and points to somewhere
within the new allocation. As the data is changed, it corrupts the
validly used memory; this induces undefined behavior in the process.
Can you assign ptr to something after it has been freed?
int * ptr = (int*) malloc(sizeof(int)); /* line 1 */
free(ptr); /* line 2 */
ptr = (int *) malloc(sizeof(int)); /* line 3 */
Taking your question as:
"Is it legal to assign the address of freshly, dynamically allocated memory to a pointer (line 3), after the memory this pointer pointed to from a previous dynamical allocation (line 1) had been freed (line2)?"
Then this answer is yes.
Running line 3 would also be valid without having run line 2. Still, if not calling free() (line 2), the value assigned to ptr (line 1) is overwritten (line 3), and with this the possibility to call free() on ptr's initial value is lost, which in turn leaves the program with leaking exactly this memory allocated initially.
Is this legal to do? Can you assign ptr to something after it has been freed?
Yes, this is legal. ptr can be reassigned as many times as you want. Freeing that pointer is not necessary for reassigning it, for example
int * ptr = malloc(sizeof(int));
int *temp_ptr = ptr; // temp_ptr is pointing to the location ptr is pointing
ptr = malloc(sizeof(int)); // ptr points to new location.
Note that you should not cast the return value of malloc.
Yes you are assigning new memory on heap and its legal.
I would recommend you use realloc instead.
For the case when realloc() fails, from c11, chapter §7.22.3.5,
The realloc function returns ... a null pointer if the new object
could not be allocated.
and
[....] If memory for the new object cannot be allocated, the old
object is not deallocated and its value is unchanged.
The proper way of using realloc will be
ptr_new = realloc(ptr, sizeof(int)*2);
if (ptr_new == NULL)
{
free(ptr);
}
Also please read why should i not cast return value of malloc.
Yes. It is perfectly legal. ptr is a standalone variable that continues to exist regardless of its contents. Nothing happens to the memory location where ptr is stored. There is nothing to prevent you from assigning you any value to it. The correctness of the memory allocation ( malloc / realloc etc) is a different story, but there is nothing wrong with reusing a variable (a memory location) to store the address of a memory location.
When you declare a pointer it will be allocated for it a memory location. That location can be reassigned.
If you reassign it after having assigned it a value with a malloc() call and before to free() it, this is a memory leak. After free() you can reassign it and no leak will happen, do not forget to free() it again.
In fact, the operating systems that are useful programs that never finish will reassign all the time some fixed pointers toward processes, free them when the process finishes, etc.
The programming in which assignments are not allowed is called functional programming.

dynamiclly allocate and free in C

void* heap = malloc(100);
char *c = heap;
strcpy(c, "Terence");
printf("heap = %s\n", heap);
free(heap);
heap = malloc(100);
printf("heap = %s\n", heap);
the output is:
heap = Terence
heap =
That is what I expect, but now I have a far more complex code, the structure is similar to the above, but the output is like:
heap = "Terence"
heap = " ren "
something like that.
It seems heap has not been cleaned up?
Is there a way to solve it?
The region of memory allocated by malloc has an indeterminate initial value.
From the C Standard (emphasis mine):
(c99, 7.20.3.3p2) "The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate*."
Use calloc or memset after malloc to have a determinate value.
Malloc does not implicitly zero out the allocated memory. You need to cell either calloc or memset for this purpose:
heap = malloc(100);
memset(heap, 0, 100);
or
heap = calloc(100, 1);
When you use void free( void* ptr ); to release a previously allocated memory block, you use the pointer variable as an argument to the free function. The function only reads the pointer variable, and does not automatically set it to NULL for you.
Therefore, it is up to you to set that variable to NULL, so that other code you have written, which may depend on that variable, will be dealing with a NULL pointer, instead of a memory address that looks OK but points to memory that cannot be accessed any longer.
When you free any memory block you should always set the pointer variable to NULL, because the memory is no longer accessible.

Resources