When dynamic variables are released from memory in C? - c

I would like to know, when is the pointer p released in the code? Is it considered as a local variable and released at the end of foo function?
Also, when is *p released? I'm assuming it's never released.
I know that free releases the memory allocated by malloc. But I'm having trouble understanding the difference between p and *p, which one is considered to be "the memory" which is released ?
int foo()
{
int *p = (int*) malloc(sizeof(int));
.
. //free is not called
}

Inside a function body, int *p tells the compiler (or C implementation) to allocate memory for p. This allocation is automatic, and the release of the memory used for p is automatic when execution of the block the declaration is in ends.
When malloc(sizeof(int)) executes, it attempts to allocate enough memory for an int. This allocation is manual. The memory is released only when the program executes a call to free or some related routine that frees memory (such as realloc to allocate new memory and free the old memory).
The allocations of the memory for p and the memory that p points to are unrelated. There is no binding between p and *p other than the fact that the address of *p is is stored in p. You could do this:
{
int *q;
{
int *p = malloc(sizeof *p);
// Now p points to allocated memory.
*p = 3;
q = p;
// Now q points to the allocated memory.
}
// Now p no longer exists in the C model of computing.
// The memory used for p has been released.
// The memory allocated with malloc is still allocated.
printf("%d\n", *q); // Prints “3”.
free(q);
// Now the allocated memory has been released.
}

After the call to malloc, p will contain the address of the memory allocated by malloc.
So p is a (local) variable and *p is the allocated memory.
The allocated memory (*p) is released by a call to free, which never occurs in your code (this is called a "memory leak").
The local variable p is on the stack and is automatically released when the function returns (but *p is not automatically released!)

There are two pieces of memory involved - the variable p, and the int object p points to.
int * int
+–––+ +–––+
p: | | –––> | |
+—––+ +–––+
Space for the variable p is allocated on entry to foo and released when the function exits.
Space for the int object that p points to (which we refer to with the expression *p) is allocated by the call to malloc, and is not released until you call free (or until the program terminates).
When foo exits, the variable p ceases to exist. The memory that p pointed to is still allocated, but unfortunately you can no longer access it.

Related

Can't I directly put head=NULL if i want to destroy linked list and free memory?

Why do we need free()? Putting the head node as NULL does similar work, doesn't it?
Why do we need free()?
The function free is used to free a dynamically allocated memory.
Putting the head node as NULL does similar work, doesn't it?
Putting NULL in the pointer to the head node does not free all dynamically allocated memory in the list neither for the head node nor for other nodes. This leads to loosing the address of the first dynamically allocated node and as a result you will get numerous memory leaks because the memory becomes inaccessible (but not freed)..
Consider the following demonstrative program.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *p1 = malloc( sizeof( int ) );
*p1 = 10;
printf( "*p1 = %d\n", *p1 );
int *p2 = p1;
p1 = NULL;
printf( "*p2 = %d\n", *p2 );
free( p2 );
return 0;
}
Its output is
*p1 = 10
*p2 = 10
In the program there is dynamically allocated a memory for an object of the type int and the address of the allocated memory was assigned to the pointer p1.
After assigning NULL to the pointer p1 the address of the allocated memory is not stored in this pointer any more.
So if the address was not assigned to the second pointer p2 then the address of the allocated memory would be lost forever and we could not free the memory.
Only due to having a copy of the address in the pointer p2 we can free the allocated memory.
Thus setting a pointer to NULL only changes the value stored in the pointer. The allocated memory is not touched in any way.
They are not equivalent.
In C, if you explicitly allocated memory (e.g., by using malloc), you need to explicitly free it (by using free).
If you just assign head = NULL, you won't be able to access the following elements in the linked list, but their memory will still be allocated - the process will still hold this memory, and you'll have a memory leak on your hand.
Because there is no garbage collector in C. This means you should collect your garbage yourself.
Everything you allocated on the heap has to be deleted manually.
Forgetting to do it is called memory leak.

What happens to a local pointer variable inside a function that has been dynamically allocated?

I'm curious to know what happens if you declare an int pointer inside a function, and then dynamically allocate it using malloc
void testing(){
int *p = malloc(sizeof(int));
*p = 5;
}
Does the data (5 in this case) live on in the heap even though the pointer is destroyed after the function is finished executing?
Memory allocated using malloc() or calloc() is not freed automatically. You have to call free() explicitly to de-allocate the memory.
// Allocate
int* p = (int*)malloc(10 * sizeof(int));
// De-allocate
free(p);
Does the data (5 in this case) live on in the heap even though the
pointer is destroyed?
Yes, it is called memory leak. You allocated memory and stored its reference in pointer p, when p is destroyed you lost only the reference to allocated memory introducing a memory leak.
In this function
void testing(){
int *p = malloc(sizeof(int));
*p = 5;
}
the local variable (pointer) p has the automatic storage duration.
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way.(the C
Standard).
The object that occupies the allocated memory with malloc has the allocated memory duration.
The lifetime of an allocated object extends from the allocation until
the deallocation. (the C Standard).
So as the memory was not explicitly deallocated then the lifetime of the object extends until the program will be finished. You can not access the object or reuse the allocated memory because the address of it stored in the local variable p is lost after exiting the function. This situation invokes a memory leak.

C - malloc and automatic storage

I understand that variables declared within a function have automatic storage. Does this mean it's not necessary to free pointers (p below) that have been explicitly allocated within a function call using malloc?
void f() {
int *p;
p = malloc(sizeof(int));
*p = 1;
printf("%p %d\n", p, *p); // 0x7fc135c02850 1
free(p); // is this necessary?
}
int main() {
f();
}
(Note that I used a pointer to an int here, but the question applies to any pointer that's a return value of malloc and friends.)
I'm guessing no, since malloc allocates memory on the heap and not the stack; thus the memory p points to won't automatically be deallocated when the stack frame for f() is popped.
p itself is automatic storage, and it will disappear when the function ends. What it points to however does need to be free()'d, at some point. For example, you could return the malloc()'d memory from the function, and free() it later on - p has still disappeared
The memory you allocate with malloc() needs to be free()'d. In your case, automatic storage applies to the variable p itself, but not to the memory you allocated! When you use free(p), you free the memory p points to and not the p variable itself.
Correct, a call to free is necessary.
If you ask for memory allocate manually, you must free manually the space you asked for. So free is necessary there

Will the Heap Scope be freed successfully while the Pointer Value was changed?

For example:
void heaptest(){
int *a;
a=(int*)malloc(1024*4);
int i=1024;
while(i--){
*a=i;
//printf("%d",*a);
a++;
}
free(a);
}
When the 'a' was used as a pointer, assume it points to address "0x20000". And the scope of this heap area is from 0x20000 to 0x21000. totally 4096 bytes.
after the while loop, the 'a' was pointed to 0x21004, which is actually out of the scope of the defined heap. if we free the heap using
free(a)
Will this heap be freed successfully?
For my observation, when I use this func in Visual Studio. it will show
Invalid address specified to RtlValidateHeap
and the value of a is 0x21004 before the free() operation whenever whether there is a printf() function in the while loop.
When I use this function on Keil-MDK for STM32F7(Cortex M7), it shows nothing but before the free operation. the value of 'a' will become 0x00000;
But when I add the printf() function shown in the code. the value of 'a' will back to the initial value 0x20000.
So, the final question is, could we change the value of the heap pointer? or assign it back to the initial value every time before the free() operation?
Will this heap be freed successfully?
It is impossible to say. You invoke undefined behavior by passing a pointer value to free() that was not returned by malloc() or one of the other allocation functions. That could turn out to manifest as freeing the block into which the pointer points, but more likely it produces an error, or worse: silent memory corruption.
Note in particular that it is the pointer value that matters. The variable, if any, in which you store the pointer value has nothing directly to do with it.
could we change the value of the heap pointer?
In the sense that the pointer is a value, no, you can no more change it than you can change the value 1. But you can cause a variable in which that value is stored to instead contain a different value. You may even be able to do so in a way that allows you to recover the original value, so as to retain the ability to free the allocated memory.
You need to free the address your were given. What you do to the code's variables in between does not matter.
This is valid:
char * p = malloc(42);
p++;
p--;
free(p);
This as well:
char * p = malloc(42);
char * q = p:
/* p += 43; */ /* Invokes UB, as making q point more then just one past the object. */
q += 42; /* Just one past the allocated memory. */
q -= 42;
free(q);
This isn't
char * p = malloc(42);
p++;
free(p);
This neither:
char * p = malloc(42);
p--;
free(p);
An address passed to free must have been obtained as the return value of malloc/calloc/etc. Passing any other pointer invokes undefined behavior.
From the MSDN page for free:
The free function deallocates a memory block (memblock) that was
previously allocated by a call to calloc, malloc, or realloc. The
number of freed bytes is equivalent to the number of bytes requested
when the block was allocated (or reallocated, in the case of realloc).
If memblock is NULL, the pointer is ignored and free immediately
returns. Attempting to free an invalid pointer (a pointer to a memory
block that was not allocated by calloc, malloc, or realloc) may affect
subsequent allocation requests and cause errors.
Keep track of the original pointer so you can later pass it to free:
void heaptest(){
int *a, a_sav;
a=(int*)malloc(1024*4);
a_sav = a; // save the original pointer
int i=1024;
while(i--){
*a=i;
printf("%d",*a);
a++;
}
free(a_sav); // free the saved pointer
}
Calling free with an argument that does not point to an adress allocated via malloc, calloc or realloc is undefined behavior. You have absolutely zero information on what it will do. Try something in this form.
void heaptest(){
// Declare a const to make sure we free the right adress in the end
int * const a = (int*)malloc(1024*size_of(int));
int i=1024;
do {
// This will loop from a[0] to a[1024] which is what I assume you meant to do
a[1024-i] = i;
} while (--i);
free(a);
}
It's hard to say if this program does what you wanted. You can change i or the index or the right hand side of the assignment to suit your needs but don't do the loop like you did because it's way more error-prone.

Use after free error?

int main(void) {
int* p = (int*) malloc(sizeof(int));
int* q = (int*) malloc(sizeof(int));
*p = 10;
*q = 20;
p = q;
printf(“%d %d”, *p, *q);
free(p);
free(q);
}
Why does the above code contain use-after-free error? There's no more expression after free(p) and free(q). Obviously we are not using them anymore!
You have two problems here.
First, you are deleting the same heap variable twice:
free(p);
free(q);
Second, you have a memory-leak, because the variable created by p is no longer accessible.
Notice that onebyone's comment is really important. If you change the line:
p = q;
into:
*p = *q;
There would be no problems at all in your code :) Hello Pointers!
You set p to q, so you are free()ing it twice.
Since q and p point to the same memory at the point you are freeing them, you're effectively freeing the memory twice.
Because here:
p = q;
...you're throwing away the old value of p. You now have two copies of the pointer that was returned by the second malloc, and none of the pointer that was returned by the first malloc.
So then here:
free(p);
free(q);
...the same pointer value gets passed to free twice: use-after-free error. The other pointer value never gets passed to free at all: memory leak.
It's a fundamental memory manipulation error!
Never do so!
You allocate memory at pointer p and after that you just rewrite pointer at p=q.
Previous value of pointer you lost, p is a lost pointer!
You can never free the memory allocated above for pointer p! It's a lost memory block for p.
It's memory leak... Try to free it at line free(p) in real free memory allocated for pointer q, but not for p!.
Next line free(q) is another try to free the same memory that was freed in previous line. That will be unpredictable behavior depending on the system it may be nothing special, and may be an error at program finish.
You must replace line free(p) before line p=q.
And always before rewrite pointer with previously allocated memory free them! Consider it a strict rule!

Resources