I have a question regarding free() in C.
Suppose I have a pointer to some struct (say node *ptr).. after freeing it can i Initialize it to NULL and make it point to some new location using malloc() or realloc()?
For Example:
node *ptr=NULL;
ptr=realloc(ptr,sizeof(node)); //works exactly like malloc
/* Do some operations on ptr */
free(ptr);
ptr=NULL;
ptr=realloc(ptr,sizeof(node));
Is that valid, or will it create a problem.
The reason I used realloc in place of malloc is because all my realloc() calls are in a loop (so instead of sizeof(node) in the second argument it is actually n*sizeof(node) where n keeps on incrementing... and the last location in this resultant array is written with new data) where the memory pointed to by ptr keeps on increasing until the loop ends, at which point I do not require the data in the memory pointed to by ptr, so I think it best to free it. Now, all this is nested in one more bigger(outer) loop.
Thanks a lot for your help
It is ok - you are not really reusing the pointer but just the variable holding the pointer.
ptr doesn't remember that it was once assigned a value, and re-using it again if it was assigned NULL is no different from using it the first time around.
And since realloc() acts like malloc() when it's passed a NULL pointer, it should work just fine.
You should not thinking about it as "freeing the pointer", but freeing whatever the pointer points to. It's perfectly normal that a pointer points first to one object (which may then be freed), and then to another object.
Related
I'm allocating an array of of "Todo" structs on the heap like so:
struct Todo *todos = malloc(n * sizeof(*todos));
My understanding is that I have now allocated memory for all of my n Todo structs. So if I want to save some values I can just do for example:
todos[i].id = 1;
The problem now is that if I try to free that memory using free(&todos[i]); I get an error telling me that I haven't allocated that pointer.
My question is now, do I just need to free the todos array and not every element on its own?
You have allocated one single block of memory for all your Todo structures. You can not free a single element. Just like you should not free elements of a non-heap allocated array.
Each call to malloc (or calloc) should be matched by a single call to free.
A little bit of background to Some programmer dude's answer
C11 standard, 7.22.3.3 "The free function", paragraph 2:
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
[emphasis by me]
Background (second level...) is that typically, you did not only receive the memory starting at the pointer, but additionally there is some kind of (machine/OS specific) control block right before the pointer's address that is needed to free the memory again.
You might try to peek at this control block by reading some bytes right before the pointer (just out of curiosity), but be aware that this actually is undefined behaviour as well (so don't ever do this in production code!) and might lead to your programme crashing.
As a reference, always that you do:
WhateverTypeInTheWorld *var1 = malloc(whateveryouwanttocompletearray);
then, you have to do
free(var1); /* use the same value you received from malloc() */
to return the memory back... as you did only one malloc(), you can do only one free() and pass to it the same pointer you got from malloc().
When you write:
free(&todos[i].i);
you are passing free the i-esim element field i's address, and not the pointer you received from malloc(). Probably you understood that you can free part of the memory you received... but it doesn't work that way... you get the memory in chunks, and you have to return it in those same chunks you received from malloc.
I have a c function that looks like this
void fn(void *data) {
type *p=malloc(sizeof *p);
p=data;
...
free(p);
}
If I understand correctly, the two problems with this are that the malloc sets aside some memory for p, but the pointer in p is then immediately overwritten by the pointer data so nothing is pointing to the memory allocated to p. Also, the subsequent free actually frees the memory at data so that whatever function called fn will no longer be able to safely access it. Is this right?
What I probably meant to do is:
void fn(void *data) {
type *p;
p=data;
...
}
Since there's no malloc there's nothing to free and the pointer in data continues to point to allocated memory?
EDIT: I should point out that I know for sure that the pointer in data is actually a pointer of the same type as p.
FURTHER EDIT: The pointer in data points to something that was malloc'd elsewhere.
Yes. You understood right. Assigning data to p after allocating memory to p will leave no pointer to the allocated memory by malloc.
A block of memory that's no longer accessible to a program is said to be garbage. A program that leaves garbage behind has a memory leak.
Unfortunately, unlike some other languages, C doesn't have garbage collector.
Another thing is that calling free(p) will invoke undefined behavior because the argument to free must be a pointer that was previously returned by a memory allocation function (or it could be a NULL pointer).
Yes, the function should not free the memory it did not allocate. The principle worth following in most cases is: do not allocate and deallocate in different contexts.
I have a program in which I need to work with pointer arrays. My problem is that I do not know how to delete element i from pointer p (p[i]). I will detail the problem below.
I have the structure:
struct CuttingLine
{
NxU32 linePoints[150];
NxU32 lineLength;
NxVec3 normal;
};
Then I declare the pointer:
CuttingLine* cuttingLines;
I initialize the pointer like this:
cuttingLines = (CuttingLine*)malloc(sizeof(CuttingLine) * 10);
And then I add some elements to it (please notice that this is just for demonstration purposes, in my program, line is created and given values):
for(int i=0;i<3;i++)
cuttingLines[i] = line;
Then I want to go through the pointer again, and delete the three elements, but not free the pointer (I understand that you can delete the pointer by calling free(cuttingLines)).
How can I do that? I just want to delete the elements inside it, but not deallocate the memory allocated in the beginning.
Because cuttingLines is a pointer to CuttingLine, your loop is actually performing a structure copy of line into each of the three positions. There is no need to delete these deep copies. You just have to not use the information anymore when you are done with it, and note that the cuttingLines variable contains unused data. You can then reuse the cuttingLines variable later (filling it with new lines) at your convenience.
To me it looks like you want to have an array of pointers, and dynamically allocate the elements of the array. In this case you'd want to set the value of the pointer to NULL, which means the pointer doesn't point to anything. Like this:
cuttingLines[i] = NULL;
This means "I have a pointer in my array but it doesn't point to anything".
However if you don't free the memory (by calling free(cuttingLines[i])) you will have a memory leak, so remember to free the memory later in your program. For this you will need to have another pointer somewhere that points to whatever each call to malloc returned.
Just to be pedantic: you can't free a pointer (except in the sense of allocating e.g. sizeof(CuttingLine*) using malloc); you can free memory, so calling free(ptr) frees the memory pointed to by the pointer. Also, you treat cuttingLines like an array of pointers, i.e. pointer of pointers, so its type should be CuttingLine** and you'd declare and allocate it by:
CuttlingLine** cuttingLines;
cuttingLines = (CuttingLine**)malloc(sizeof(CuttingLine*) * 10);
Also, you shouldn't cast the return value of malloc (see here) unless you're writing C++ in which case you shouldn't need to use pointers to pointers in the first place.
If on the other hand you want to have an array of CuttingLines then you're on the right track in the sense that you allocate cuttingLines correctly, and you don't need to free the memory used by individual CuttingLine. However in this case you don't know which elements in the array are valid and which aren't unless you either track the indices in the code or in the elements themselves by e.g. setting lineLength to 0 and checking its value.
It is known that if we pass a pointer by value to a function, it cannot be freed inside the function, like so:
void func(int *p)
{
free(p);
p = NULL;
}
p holds a copy of a (presumably valid) address, so free(p) tries to, well, free it. But since it is a copy, it cannot really free it. How does the call to free() know that it cannot really free it ?
The code above does not produce an error. Does that mean free() just fails silently, "somehow" knowing that address passed in as argument cannot be worked upon ?
p holds a copy of a (presumably valid) address, so free(p) tries to, well, free it. But since it is a copy, it cannot really free it.
It's not true. free() can work just fine if p is a valid address returned by malloc() (or NULL).
In fact, this is a common pattern for implementing custom "destructor" functions (when writing OO-style code in C).
What you probably mean is that p won't change to NULL after this - but that's natural, since you're passing it by value. If you want to free() and null out the pointer, then pass it by pointer ("byref"):
void func(int **p)
{
if (p != NULL) {
free(*p);
*p = NULL;
}
}
and use this like
int *p = someConstructor();
func(&p);
// here 'p' will actually be NULL
The only problem is if this function is in a different DLL (Windows). Then, it may be linked with a different version of the standard library and have different ideas on how the heap is built.
Otherwise no problem.
Passing p to func() by value, which will copy the pointer and creates the local copy to func() which frees the memory. func() then sets it's own instance of the pointer p to NULL but which is useless. Once the function is complete the parameter p come to end of existence. In calling function you still have pointer p holding an address, but the block is now on the free list and not useful for storage until allocated again.
What everybody is saying is that your memory will be freed by free(p);, but your original pointer (which you use to call the function with) will still hold the (now invalid) address. If a new block of memory including your address is allocated at a later stage than your original pointer will become valid (for memory manager) again, but will now point to completely different data causing all sorts of problems and confusion.
No you really free the block of memory. After the function call, the pointer passed to this function is pointing to nowhere : same address but the MMU don't know anymore what to do with this address
I have a pointer to a struct. I call a routine that determines whether I need this struct and allocates space for it using malloc, returning the pointer to that area or zero if unused.
struct node *node_p;
node_p = need_this();
This works and I can properly access all the elements of the struct. One of the elements of struct node is *next which points to the next node struct and a pointer to a string but it's returning a pointer to a string that doesn't even exist in this routine.
node_p=find_string(node_p->next,"string");
However, this does return a pointer in the struct to the correct string.
struct node *node_p, *node_copy;
node_copy=find_string(node_p->next,"string");
The only difference is using a second pointer instead of the original. Am I doing something wrong here or must it be deeper into the called function? The problem with blaming the called function is I use it in multiple places for months without issue, however the other calls only look for the string and never go to 'next'.
EDIT: Further debugging has shown the problem actually lies with the pointer being passed to find_string and not the returned pointer. That changes the question and the problem so I need to open another question.
In this snippet:
struct node *node_p, *node_copy;
node_copy=find_string(node_p->next,"string");
you dereference node_p when it is not yet initialized (doesn't point to a legally allocated memory block). That's undefined behavior. You should set node_p to a legally allocated memory block of appropriate size first.
You need to allocate memory explicitly for every struct, i.e. allocate a new struct and set next pointer to point to it.
Pointers in C prior to initialization point to random place and you never should dereference them. Safe policy would be to init them to be NULLs.