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.
Related
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
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.
If I allocated memory from another pointer, then declare a pointer equal to the other pointer, can I then free the memory allocated with the first pointer by using free() on the new pointer?
Example:
typedef struct foo{
int n;
char c;
} foo;
foo* bar = malloc(sizeof(foo));
foo* tmp = bar; // declaring pointer identical to other pointer
free(tmp); // can I do this to free *bar?
Yes, it is completely fine.
Your implementation of malloc will most likely mark the chunk of memory as allocated before returning a pointer to it.
Now you can have as many pointer variables as you want which point to this chunk of memory and you can free that memory by calling free on any of them.
The pointer itself doesn't contain information about whether the memory it points to has been allocated. It just points to it.
int* i = malloc(sizeof(int) * 23);
int* j = i;
free(j);
// free(i); // this is undefined behavior, the memory was already freed
Yes you can do what you are asking about. But it is not another pointer, what you are freeing is the same pointer. When malloc returns a pointer, it is essentially giving you an integer that is the address of the start of the chunk of memory that it has reserved for you. When you are done are done with the memory, you pass that address to free. As far as free is concerned, there is no difference between:
free(malloc(17));
,
void *p = malloc(17);
free(p);
or
void *p1 = malloc(17);
void *p2 = p1;
free(p2);
In all of these cases the value returned from malloc is getting to free, and that is all that matters.
I have a question in regards to creating a dynamic array.
int *p;
p = malloc( 3 * sizeof( int ) );
// initializes elements in the array
for ( int i = 0; i < 3; ++i ) {
*p++ = i * 4;
}
how can i free the memory i just allocated? for some reason, i find much easier deallocating a two dimensional array than one LOL. It's been along time since the last time i used C.
if i do the following:
free( p ); // will probably get an error.
Another thing in regards to pointers. I tried this:
int * p = malloc( sizeof( int ) );
*p = 4;
printf( "%d\n", *p ) // prints 4 as expected
free( p );
printf( "%d\n", *p ) // still prints the number 4!!!
the free function should release the block of memory that p points to. how is it that printf stills prints 4 then?
Malloc() returns a pointer to the allocated block. Keep it for future use with free().
Index your array with integer OR walk through it with a pointer, but keep the original address stored somewhere.
You can do like this
int *p = malloc(3 * sizeof(int));
for( int i = 0; i < 3; i++)
p[i] = 4*i;
// .....
free(p);
or
int *p = malloc(3 * sizeof(int));
int *q = p;
for( int i = 0; i < 3; i++)
*q++ = 4*i;
// .....
free(p);
In the first case, you just write free(p) as you only allocated one block of memory.
What you are doing in the second case is undefined behaviour. It might print 4, it might crash, it could do literally anything. The chances are that the implementation is just marking that location as reusable, but not actually clearing it out (why should it, it's a waste of time)
free(p) de allocates memory pointed by p. But p still having memory address which is de allocated by free(p). De-allocation means that block of memory added to list of free memories which is maintained by memory allocation module. When you print data pointed by p still prints value at address because that memory is added to free list and not removed.
how can i free the memory i just allocated?
You could do something like this
int *p;
p = malloc( 3 * sizeof( int ) );
// initializes elements in the array
for ( int i = 0; i < 3; ++i ) {
p[i] = i * 4;
}
this would not change p, so you could use free(p) to free it.
If you need to change p, you should remember its original value in another variable, and call free() on that original value, such as
int *op;
op = p;
/* do something that changes `p` */
free(op);
how is it that printf stills prints 4
What you did, access a dynamically allocated memory region after you freed it, will lead to undefined behavior. It could print 4, it also could crash or do something really wild.
Malloc ==> Only allocate the memory (not changing memory data to NULL )
Free ==> Only It will release the allocated resources on the pointer,(not changing memory data to NULL )
In both cases user has the responsibly to set appropriate value if required.
In first case you can still free the memory by taking the pointer back to the first element's address and then calling free(p) like:
p = p-3;
free(p);
Reason : malloc store some information about how much memory need to be freed once allocated dynamically that's why you need to point it back to the start so that free can read that information and free exactly 3 int memory allocated by malloc.
In your second case it is still printing is not universal result, output can be anything even program may crash.
Reason : free do not do anything special with the memory it only add it back to the FREE LIST it maintains for the memory available for dynamic allocation.
It is only up-to the programmer that they do not dereference the after calling free on it.
how can i free the memory i just allocated?
When we want to free a memory chunk previously allocated by malloc(), we use the free function. This function accepts a char pointer to a previously allocated memory chunk, and frees it - that is, adds it to the list of free memory chunks, that may be re-allocated. Use free(p).
how is it that printf stills prints 4 then?
Usage Of free():
Several notes about free():
The size of the chunk was stored by malloc() previously in its memory map, and that is how free() knows how many bytes to free.
The freed memory is not being cleared or erased in any manner. This is why accessing memory that was just freed often does not cause a crash - any data in it is still the same as before calling free().
The free() function cannot nullify pointers to the given memory chunk that might still exist in our program. After we call free(), it is up to us (the programmers) not to try and dereference pointers that still point to that memory chunk. Such pointers are known as 'dangling pointers' - they point to memory that was already freed, and thus they should NOT be dereferenced again, unless they are assigned the address of a different (not-freed) memory chunk.