does free() follow pointers? - c

I'm sure it doesn't, but maybe there's black magic in it, so here's my question:
If I have a struct like this:
struct mystr {
char * strp,
unsigned int foo,
};
and I allocate memory for it and want to release it later. Do I have to do
free(mystr_var->strp);
free(mystr_var);
or is the last line enought, does the free() function follow the pointers and free them two?

No, free doesn't follow pointers, you need both lines.
I usually write a function like:
void freemystr(mystr *mystr_var)
{
if (mystr_var)
{
free(mystr_var->strp);
mystr_var->strp = NULL;
free(mystr_var);
}
}

Every individually allocated block of memory must be freed individually. free() will only free the memory block that the pointer points to and its has no knowledge of what is the content of that memory.
Hence, in your case you are doing it the right way by first freeing the innermost memory allocated in a structure and finally freeing the struct pointer.
If you just do free on the struct pointer, the struct memory gets freed. The memory held by char* strp, becomes a memory leak in your program lifetime.

No, it doesn't.
It's not magic at all, to the compiler it's just another function call.
Ask youself how you would implement void free(void *); in a way that follows pointers, of course without being fooled by being given a binary data block containing anything. You can't.

No. It simply frees the block pointed to.
You need to explictly free referenced memory. You need to do this first (i.e. most likely in the opposite direction to how you allocated the memory)

No. free won't do recursive free for all members. You have to explicitly free all members for which you have allocated memory.
If you understand how memory is allocated for struct and how free works this won't be a problem.
struct mystr {
char * strp,
unsigned int foo,
};
when you allocated memory using malloc & friends, it only allocates memory for the members.
In your case one char* and one unsigned int. Note that it doesn't allocate any memory for storing data in the char*. So you have to allocate memory for strp again before storing data. Except when you directly assign string literals Or just use the pointer strp to point to an existing memory.
Example:
case 1:
struct mystr s;
s.strp = "literals"; // valid, no need to malloc
case 2:
char *p="abc";
s.strp = p; // valid, no need to malloc
On all other usages, you must allocate memory for strp before storing data into strp.
So when you call free on the struct variable, it only frees the pointer allocated for strp and not the memory which is pointed to by strp.
It's simply because free has no information about where strp points to.
Note that in the above two examples, you don't free strp as you didn't allocate any memory there for storing data into strp. Simple rule is one free for one malloc/calloc/realloc.

C99 says,
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 the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

Related

How to free() an array of structs allocated by malloc()?

I've been working on a project that uses structs as storage for strings. I declared a struct consists of char type members:
struct datastore1
{
char name[50];
char address[50];
char email[50];
char number[50];
char idnum[50];
};
I'm aware that I can just do char *name, char *address... but let's say we specified it with max length of 50. Then on my function which uses the struct, I malloc'ed it with index size of 30:
struct datastore1 *dsdata = malloc(30 * sizeof(struct datastore1));
Supposedly I finished copying all strings into the struct by accessing each index, How should i free the allocated memory that was used after calling malloc? I tried doing free(dsdata) on the end of the program but I am not sure if it's the right way. Should i free each indexes individually? Please enlighten me. Thank you in advance for the feedback!
How should i free the allocated memory that was used after calling malloc?
Consider below example,
struct datastore1 *obj1 = malloc(sizeof(struct datastore1));
free(obj1);
Here obj1 is pointing to the block of memory of size same as size of datastore1 in order to free you need to send the address which is allocated by malloc.
likewise,
struct datastore1 *obj2 = malloc(3 * sizeof(struct datastore1));
free(obj2);
obj2 is pointing to a block of contiguous memory of size 3 * sizeof(datastore1) you need to pass the base address to free
Should i free each indexes individually?
NO, Since block of memory is allocated only once and you need to free exactly one time.
Let me extend it further,
struct datastore1 *obj3[3];
for(int i=0;i<3;i++)
obj3[i] = malloc(sizeof(struct datastore1));
for(int i=0;i<3;i++)
free(obj3[i]);
Here obj3 is array of pointer and each index is pointing to different part of memory and hence need to be freed individually.
Note: For simplicity I haven't considered return value from malloc. Null check has to be done on malloc return value.
1.
How should I free the allocated memory that was used after calling malloc?
I tried doing free(dsdata) on the end of the program but I am not sure if it's the right way.
free(dsdata) is fine, since you allocated the whole space by just one call to malloc with:
struct datastore1 *dsdata = malloc(30 * sizeof(struct datastore1));
To cite the standard (C18), 7.22.3.4 - "The malloc function" (emphasize mine):
7.22.3.4 The malloc function
Synopsis
1
#include <stdlib.h>
void* malloc(size_t size);
Description
2 The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.
Returns
3 The malloc function returns either a null pointer or a pointer to the allocated space.
It is correct to use free(dsdata) because malloc allocated all of the required space at once and returned a pointer to the first structure variable of this array which is assigned to the pointer of dsdata.
The free() function "knows" that dsdata is a reference to the whole allocated space. You do not need to free each of the 30 structures of type struct datastore1 in memory individually.
2.
Should I free each indexes individually?
No, you do not need and even more important you should not do so; this would be Undefined Behavior:
Citation from the current standard (C18), 7.22.3.5/3 - "The free function" (emphasize mine):
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.
As far as I understand you only used malloc to allocate space for an array of datastore1 struct, so it is sufficient to just do free(dsdata).
If in the struct you would have pointers and you would use malloc to allocate each of them, only than you would need to free each of them first.
Both answers above are correct, but to fully understand how does it work I recommend you to learn how to use valgrind.
To check if program released memory correctly use
valgrind -v --leak-check=full --track-origins=yes ./your-program
This will execute your program on valgrind's virtual processor and give you full feedback about used resources.
Basically operator [] in C programming language in array definition context causes creation of (lets say to simplify) static array - this means that array is included in size of structure (if defined as part of structure) or is stored on the stack (if defined in function or globally).
The malloc function returns address of block of data you can use. Size of this block is at least as big as you requested. When you use free you release this block wich in this case means all data in block pointed by this address will be released.

Correct usage of free() function in C

I am new in C programming language so can you tell me if this is correct way to do.
for example:
program points on buffer and i use that pointer as parameter in free() function. So, what problems can this function cause ?
You should call free only on pointers which have been assigned memory returned by malloc, calloc, or realloc.
char* ptr = malloc(10);
// use memory pointed by ptr
// e.g., strcpy(ptr,"hello");
free(ptr); // free memory pointed by ptr when you don't need it anymore
Things to keep in mind:
Never free memory twice. This can happen for example if you call free on ptr twice and value of ptr wasn't changed since first call to free. Or you have two (or more) different pointers pointing to same memory: if you call free on one, you are not allowed to call free on other pointers now too.
When you free a pointer you are not even allowed to read its value; e.g., if (ptr) not allowed after freeing unless you initialize ptr to a new value
You should not dereference freed pointer
Passing null pointer to free is fine, no operation is performed.
Think that the computer has a whole bunch of memory not (yet) used by your program. Now you need some more memory and you ask your computer to give you some more (for example, a large buffer). Once you are done with it, you want to return it to the computer.
This memory is called the heap. You ask for memory by calling malloc() and you return it by calling free();
char *buffer;
buffer = malloc(512); // ask for 512 bytes of memory
if (buffer==NULL) return -1; // if no more memory available
...
free(buffer); // return the memory again
free() function is used to deallocate memory used by one program and move it back to available memory area so that other operating system processes can use that memory location. Also free function takes any type of pointer that points to that memory location.
For example:
int a = 10; // suppose 2 byte is allocated ie location 1000 and 1001
Now this 2 byte of memory belongs to specific problem; hence OS will not give this memory location to another process (memory is now allocated memory not available memory)
int *ptr =&a;
/*ptr is pointer variable pointing to 1000
as it is int pointer therefore ptr++ will move pointer to 1002*/
Now if we do free(ptr), it will check the pointer type and depending on type free function deallocate memory in this case 2 bytes starting from 1000.
Now interesting point is your data will be there until OS allocates this memory to some other process and that process overwrites it.
Also ptr is pointing to 1000 even after free() function but that memory location does not belong to our program hence ptr pointer has given new name DANGLING POINTER.
*ptr may or may not give the same value therefore it is better to make ptr =null.
From the man page of free() function:
The free() function frees the memory space pointed to by a pointer ptr which must have been returned by a pre‐
vious call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called
before, undefined behavior occurs. If ptr is NULL, no operation is performed.
You have to use the free() function when you are allocating the memory dynamically.
If you are using that as a static variable then it may lead to unintended behavior.
char *c=malloc(100);//allocating the 100 bytes of memory for a pointer variable c.
Here after usage of that varaible you can free that allocated memory,
free(c);
If you are declared a variable like this,
char c= malloc(100);// It is illegeal. And c will have a memory in stack.
If you free this variable,
free(c);//it will lead to system crash. Because your freeing the memory which is in stack memory.

Do I understand the memory problems with this malloc/free combo?

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.

Does free() free memory at all depths or only at the highest level?

Suppose I have a struct defined this way:
struct myStruct{
data* anotherStruct;
}
Suppose I allocate memory on the heap for a struct of type myStruct. The pointer to this struct is called ptr. I then call free(ptr). Does this free the memory allocated just for myStruct, or does it free the memory allocated for myStruct and anotherStruct?
If it frees only the memory allocated for myStruct, does this lead to a memory leak because there is no pointer to anotherStruct and that can never be freed?
It frees only the memory allocated to that address. i.e: Yes the highest level.
Does this free the memory allocated just for myStruct, or does it free the memory allocated for myStruct and anotherStruct?
It only frees memory allocated to myStruct.
If it frees only the memory allocated for myStruct, does this lead to a memory leak because there is no pointer to anotherStruct and that can never be freed?
If you don't have a pointer to anotherStruct then yes it leakes the memory. The usual strategy is to deallocate memory in reverse order of the order you allocated it.
For ex: In your case you first allocated myStruct and then anotherStruct, So you should deallocate in exactly inverse order, i.e: free anotherStruct first and then myStruct.
Only the highest level. It's not quite that smart.
In the code
struct myStruct *ptr = malloc(sizeof(myStruct));
.
.
.
free(ptr);
nothing shown has affected the anotherStruct member of *ptr, ptr->anotherStruct. You'd probably want to use malloc to point ptr->anotherStruct to a useful block of memory. You'd then have to call free(ptr->anotherStruct) before calling free(ptr) to avoid any memory leaks.
It can be quite useful to define initialization and destruction functions in order to handle such "internal (de)allocation" automatically.
"free" can only free the memory allocated at the highest level. The simple reason being, for the pointer members inside a struct, you may or may not allocate memory from the heap. How will free be able to keep track from where all pointer member's memory came from?
it only frees the the memory allocated to that address, if you would like to free the whole chained list then you will have to loop through it and free one element each time (a struct in your case), you will have to save the address to the next struct free the actual pointer then move to the next one and keep doing till you reach the pointer that points to null.
Address is the key for freeing memory. each malloc() returned memory is a separate key. so upper block(i.e memory allocated for myStruct type) only freed and leads to memory leak.
Best practice is to free those internal blocks, then free the upper one. otherwise you will loose the pointer address if not stored anywhere.
Yes, as everyone said , it will free the memory allocated only for the struct, NOT what the anotherStruct points to. it will certainly make memory leak. it is programmers responsibility to free the memory allocated dynamically.
you can use a tool "valgrind" to check the memory leak.

C struct memory management

Another C question:
let's say I have a struct that has a pointer member of char* type.
When I want to initialize an instance of the struct I call malloc:
MyStruct* ptr = (MyStruct*)malloc(sizeof(MyStruct)
And then allocate 256 bytes of memory for the char* member:
ptr->mem = (char*)malloc(sizeof(char)*256);
what happens to the pointer member and the memory it points to when I call
free(ptr);?
when I check the program with valgrind I see that I have a memory leak, but when I explicitly call free(ptr->member); I still have a memory leak and valgrind shows an "Invalid free" error
What's the proper way the manage the memory pointed by the member?
You have to free ptr->member first, then the struct
free(ptr->member);
free(ptr);
As soon as you call free(ptr), none of the members in ptr are valid any more. You can't do anything with them. But the memory that was pointed to be ptr->mem still needs to be freed. So you must either free(ptr->mem) first, or have otherwise copied that pointer somewhere so have a valid pointer to free.
The general pattern of allocating and freeing compound structures is something like (and it is helpful to wrap them up in nice clean functions that do this):
MyStruct* MakeMyStruct() {
MyStruct* ptr = malloc(sizeof(MyStruct)); //N.B. don't need cast if it's C
ptr->mem = malloc(sizeof(char)*256);
//initialise other members
return ptr;
}
void DestroyMyStruct(MyStruct *ptr) {
//Free members first, then the struct
free(ptr->mem);
free(ptr);
}
If some of the members are complicated structs themselves, they would in turn be allocated/freed with MakeWhatever and DestroyWhatever instead of malloc and free in the above two functions.
The rule of thumb is that you need one free for every (successful) call to malloc (and generally, these occur in the reverse order).
If you only free(ptr), then you have a memory leak (because there's no way to access the memory allocated for ptr->mem). If you only free(ptr->mem), then you haven't cleared up completely (not quite as bad as a memory leak).

Resources