C struct memory management - c

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).

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.

free(struct variable) doesn't clear previous stored values associated with that variable when I malloc again?

I created a struct like the following:
typedef struct header{
int hc;
char src[18];
char dst=[18];
char reason[15];
char d[3];
char m[3];
char y[4];
struct measurements{
char h_ip[17];
int h_ttl;
int h_id;
float h_rtt;
}HOPS[100];
}HEADER;
INSIDE MAIN:
HEADER *head;
for(...){
head=(HEADER*) malloc(sizeof(HEADER));
.....
free(head);
}
Will the above malloc automatically allocate memory for the inner struct as well? Also, I'm facing a weird problem here. After I free the header, I'm still able to print the values of head->HOPS[i].h_ip. Should I explicitly free the inner struct as well so that even the values get cleared?
Yes, it allocates memory for the inner structure. And you need not free the inner structure separately.
If you have a pointer defined inside your structure, in that case you have to allocate separately for that pointer member of the structure and free that separately.
Consider freeing memory as a black box. All what you know is that after freeing you shouldn't refer to freed memory.
You may find that that memory block still exists and still contains some old values. That's ok: it just was marked as freed and probably it will be used again soon by allocator.
For example when you call malloc again and realized that just allocated block contains values from the old structure. It happens and that's alright. Just use this block as usually.
So, after the problem with the wrong declaration of head was resolved:
free returns a previously allocated memory block to the heap. It does not clear anything (for performance reasons). However, you are not supposed to access that block anymore afterwards. Doing so results in undefined behaviour and might let your computer fly out of the window.
Worst that can happen is ... nothing ... Yes, you might even not notice anything strang happens. However, that does not mean your program run correctly, it just does not show any symptoms.
To catch illegal accesses, you might set the pointer to NULL once you freed the object it points to. Some operating systems catch accesses to addresses near the null pointer address, but there is no guarantee. It is a good practice anyway and does no harm.
For your other question: malloc allocates a block of memory large enough to store that many bytes you passed as argument. If it cannot, it will return a null pointer. You should always check if malloc & friends returned a valid pointer (i.e. not a null pointer).
int *p = malloc(sizeof(int));
if ( p == NULL ) {
error: out of memory
}
...
Notice the omission of the cast of the result of malloc. In C you should not cast void * as returned by malloc & friends (but also elsewhere). As much as you did not for free(head). Both take the same type: void *, btw. (so why cast one and not the other?). Note that in C any object pointer can freely be assigned to/from void * without cast. Warning functions are no objects in the C standard!
Finally: sizeof(HEADER) returns the size of the struct. Of course that include all fields. A nested struct is a field. A pointer to another struct is a field. For the latter, however note: the pointer itself is a field, but not what it points to! If that was another struct, you have to malloc that seperately **and also free seperately (remember what I wrote above).
But as you do not have pointer inside your struct, that is not your problem here. (keep it in mind, if you continue programming, you will eventually need that!)

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() follow pointers?

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.

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.

Resources