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
Related
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.
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.
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.
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.
I've just written a function that returns a pointer to a block of memory allocated by malloc. If I call free() on the returned pointer, will this free the memory?
I tried reading up on this, but I can't find anything that says whether you can call a different pointer pointing to the same location and whether that will free all the memory or not.
This is probably majorly basic, I think I can't find the info because I'm searching for it wrong.
Any help appreciated!
Yes calling free will free the memory. Its not the pointer that get freed but the memory that the pointer points to that is freed.
You must pass to free() the value obtained from malloc().
int *x = malloc(42 * sizeof *x);
int *p = &x[0];
free(p); /* ok, same as free x; x and p have the same value */
Edit: another example
int *x = malloc(42 * sizeof *x);
for (k = 0; k < 24; k++) *x++ = 0; /* zero first 24 elements */
free(x - 24);
It's not entirely clear what you're asking here, but if what you're asking is:
Can I call free() on a pointer which points to a location within the allocated block?
then the answer is "no" -- you must pass free() the exact pointer which you got back from malloc(). Trying to free() an internal pointer, or a pointer to memory which was not allocated by malloc(), memory corruption or a crash are likely to occur.