How can I use free when I used ** ( double pointer )? - c

STUDENT ** list=NULL;
char *getid;
getid =(char*)malloc(sizeof(char) * 8);
printf("How many student? ");
int menuNum,num=0;
scanf("%d",&num);
list=(STUDENT**)malloc(num*sizeof(STUDENT*));
I used pointer like this.
As I learned from the professor, before finishing my code, I ought to use free() function to retrieve the allocated memory again.
Here s what i wanna ask you.
I learned that If i wanna use free() about (char *getid)
I know I should write
free(getid);
then How can I use free about
STUDENT ** list = NULL ; // **It's about struct**
Should I use like
free(list);
or
free(*list);
I think the former is right, but when I write like the latter, there's no error on my X-code.
Could you tell me about it ?

You should use:
free(list);
but when I write like free(*list);, there's no error on my X-code
That's why *list does not deallocate anything, since nothing is allocated there. However, your program suffers from a memory leak that way, since the memory pointed to by the double pointer named list is not free'd. However, you are just (un)lucky not to see your program crash.
If you used Valgrind though, you would see the memory leak.
Should I write malloc and write free() immediately? not in the end of the line?
No. You first allocate the memory dynamically with malloc(), then you use this memory (initialize, access, etc.) and when you do not need the memory anymore, and only then, you deallocate it with free().
However, if you had dynamically allocated space for list[i], then you should do:
free(list[i]);
free(list);
where the order matters, since you do not want to have tangling pointers!
Maybe my example on dynamically allocated a 2D array will more explanatory on this, even though it's a different data structure than a list.
PS: We don't cast what malloc returns.

You should free any memory allocated by malloc with free...
as you figured out, you requested 8 bytes of memory and saved the Pointer to it to your symbol getid (getid =(char*)malloc(sizeof(char) * 8);)
as for your list, this is a bit trickier:
You actually allocating a list of pointers that should point to other memory locations (those might be dynamically allocated as well)
list=(STUDENT**)malloc(num*sizeof(STUDENT*)); size of num pointers
Allocates the space for the list and saves the pointer to it at symbol list.
I'd remind that the memory allocated doesn't have to come initialized from the OS, so we should initialize it.
for(int i=0; i<num; i++)
{
list[i] = NULL;
}
You could also use memset(list, NULL, num * sizeof(STUDENT*)).
and you are very much correct you should free its memory by free(list),
But you should free the items in the list BEFORE you free the list of pointers itself. (again, if the items were dynamically allocated!)
for(int i=0; i<num; i++)
{
if(list[i] != NULL) // only if allocated.
{
free(list[i]); // free the element # position i
list[i] = NULL;
}
}

Related

Free pointer to an array

In my program I have a structure that looks like this:
struct structure {
int n;
int *arr;
};
And I allocate memory for arr like this:
structure->arr = malloc(sizeof(int) * arr_size);
Now here is where I start to get confused, and I am not sure if I am doing it right. What I want to do is use "arr" as an array to store or access integers. So I set arr to point to an array that I created and filled with 0's:
int new_arr[i];
structure.arr = new_arr;
I am not sure if this is right, but so far I don't get any errors. So I create another array that stores these structures, and I insert some new structures in it. But when I try to free the member arr from any of the structures inside the array (like this free(&array_of_struct[i].arr);) I get an error:
==747==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7fffd7c6ad08 in thread T0
SUMMARY: AddressSanitizer: bad-free (/lib/x86_64-linux-gnu/libasan.so.5+0x10d7cf) in __interceptor_free
==747==ABORTING
So I think I understand what the problem is, but I have no idea how to solve it. I don't imagine this is the way I'm supposed to point to an array, so can anyone tell me how to do it right?
UPDATE
So instead of writing "structure.arr = new_arr" I am now using memset this way:
memset(structure.arr, '\0', array_size * sizeof(int));
But I still get the same arror when trying to free structure.arr. Also if I try to use mempcy. Could there be something wrong with free(&array_of_struct[i].arr)?
UPDATE2
So I actually managed to use mempcy and free member "arr". The problem is, that I can only do it before I append the structure to my array of structures. If I try to free it after that (as a member of the array) I get the errors.
LAST UPDATE
I have managed to make it work with memset. The problem was that I had to write free(array_of_struct[i].arr) instead of free(&array_of_struct[i].arr)
Thank you all for the help.
Don't do this:
structure.arr = new_arr;
That's not a copy of array content. That simply reassigns the pointer.
That means you are replacing the pointer with an allocation from somewhere else. At best, you'll have a memory leak from not freeing the original allocation. At worst, you'll crash because you attempt to free new_arr which is a stack array (invalid to invoke free on that address).
Do this instead, copy the array contents instead of overwriting the pointer:
memcpy(structure.arr, new_arr, arr_size * sizeof(int));
But if you just want to "zero out" the original allocation (as you implied), you just need to do this:
memset(structure.arr, '\0', arr_size * sizeof(int));
Or just use calloc instead of malloc to allocate and zero-out the contents at the same time.
structure->arr = calloc(arr_size, sizeof(int));
Update
But I still get the same arror when trying to free structure.arr. Also if I try to use mempcy. Could there be something wrong with free(&array_of_struct[i].arr)?
You need to pass to free exactly what was assigned from malloc.
So instead of this:
free(&array_of_struct[i].arr);
This:
free(array_of_struct[i].arr);
int *p = malloc(size);
int arr[size];
p = arr; // Not good. The memory we allocated above is now lost.
free(?); // We don't have a pointer to the allocated memory
int *p = malloc(size);
int arr[size];
int *q = arr;
p = arr; // Ok, because we have saved the pointer so we can free later
free(q);
int *p = malloc(size);
int arr[size];
memcpy(p, arr, size * sizeof *p);
free(p); // Works fine. We have not overwritten the pointer
You get this error since you can free only memory that was malloc'd.
when you write int new_arr[SIZE] you allocate the array on the stack, so you don't need to free it (you can say it will be "freed" when you leave the function in which you allocated it).
As for your struct, if you're aiming for an array that has a constant size that you know in advance, I would recommend that you implement it like this:
struct my_struct {
int arr[SIZE];
}
This will allocate the array as part of the struct (in my opinion this is more readable). So when you define an instance of this struct in your program it's sufficient to write:
struct my_struct s;
and the array will be allocated as well. In this case, you won't need to free it since you won't malloc it.
If you don't know the size of the array in advance, then it would be better to first allocate the memory using malloc and then use memcpy like #selbie suggested.

Free an array of struct

#include<stdlib.h>
#include <stdio.h>
#include <string.h>
struct t {
int value;
};
int main (void) {
struct t *a = malloc(6*sizeof(struct t));
struct t *b = malloc(sizeof(struct t));
struct t *c = malloc(sizeof(struct t));
c->value = 100;
struct t *d = malloc(sizeof(struct t));
d->value = 100;
struct t *e = malloc(sizeof(struct t));
e->value = 100;
memcpy(b, a, sizeof(*a));
int j = 0;
while (j<6){
a[j] = *c;
j++;
}
int t = 0;
while(t < 6){
free(&a[t]);
t++;
}
free(a);
}
I'm trying to free the elements inside the array one by one. But this code cannot run so I think there might something wrong with free inside the second while loop. After I changed the second while loop to:
while(t < 6){
printf("%d",a[t].value);
t++;
}
It will run. Any idea how can I free those elements?
Thanks!
I'm trying to free the elements inside the array one by one. But this code cannot run so I think there might something wrong with free inside the second while loop.
Yes, what's wrong is the attempt to free the elements one by one.
You cannot free allocated memory in different divisions than it was allocated in. The argument to free() must be a pointer value that was previously obtained from an allocation function (and not since freed). The free() call will then free the entire block. It cannot see any subdivisions of that block that you may be using, and it would be unlikely to be able to honor them even if it could see them.
Any idea how can I free those elements?
Free the whole block at once, after you're done with all the data within. That is, just
free(a);
(And also, free(b), free(c), etc.)
One free per malloc'd block.
When you malloc, you are not grabbing memory for each struct. You are grabbing one block (per malloc call) that happens to be large enough to fit 6 structs for a and 1 struct each for the others. You can only free each block of this block at once. In this case you should be freeing a through e (which are addresses returned by malloc assuming you had enough memory).
You could if you really needed to, malloc an array of struct * then malloc blocks into those struct *, but why would you in this case where the struct is small and easily copied?
The key is this: When you allocate a block of memory, malloc (calloc or realloc) will return a pointer to the beginning address in that block. You have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. free() must be passed the same address returned by malloc().
You can not provide an address from the middle of the allocated block to free(). Why? Because that will not be an address originally returned by a previous call to malloc, calloc or realloc. That is a requirement, see the man-page for free() (man 3 malloc)
The free() function frees the memory space pointed to by ptr, which must have
been returned by a previous call to malloc(), calloc(), or realloc().
So you can only make a call to free() providing a pointer holding an address that was previously allocated and returned by malloc, calloc or realloc. In your case that is a, not &a[1] ... &a[5].

defining a global struct pointer in C?

I need to identify a global struct (array), consisted of 4 integers.
The problem is, size of that struct array is not known in advance.
I'm trying to make sth. like this:
typedef struct
{
int value;
int MAXleft;
int MAXright;
int MAX;
} strnum;
int main ()
{
int size;
scanf("%d", &size);
strnum numbers[size];
return 0;
}
I heard that, it is possible to do this by pointers but I don't know how to do.
You can allocate the space for several structures dynamically like this:
strnum *numbers = malloc( size * sizeof(strnum) );
Then you can use it like any regular array (mostly).
It might be more convenient to use calloc instead of malloc. It allocates a number of blocks and fills them with zeros. Please note, that malloc doesn't clear allocated memory.
strnum *numbers = calloc( size, sizeof(strnum) );
When you are done with the memory don't forget to call free( numbers ), which will return the allocated memory back to a memory manager.
If you don't free it when it's no longer required and allocate some more and more, a memory footprint of the program will grow for no good reason as the program continues to work. This is called a memory leak and should be avoided. It might eventually result in the lack of memory for a program and unpredictable results.
And don't forget to include a stdlib.h header with prototypes of memory allocation functions.
You can start with malloc() and then do realloc() when the size keeps increasing.
I would suggest you to allocate a pool of 10 structures at once so that the number of calls to realloc() are reduced.
It is called Dynamic Memory Allocation
The thing you are trying to do can be done as follows:
strnum* number;
int size = 0;
scanf("%d",&size);
number = malloc(size * sizeof(strnum));
Also, don't forget to free the memory once you have done using the array.
free(number);

how do I release a struct from memory and arrays within them

I want to know how I can release a struct properly from memory and completely wipe it. I also need to wipe arrays or values within this struct. I tried just overwriting the struct with new data everytime the data changed but I observed a steady rise in memory use until I get a memory warning so I think my safest bet is to completely wipe the data first and then write to it again.
typedef struct {
SInt16 *array1;
SInt16 *array2;
} myStruct, *myStructPtr;
myStructArray myStruct[16];
for(int i=0;i<16;i++)
{
myStruct[i].array1 =
(AudioUnitSampleType *) calloc (asize, sizeof (SInt16));
myStruct[i].array2 =
(AudioUnitSampleType *) calloc (asize, sizeof (SInt16));
}
free(myStructArray) // throws SIGBART error
You didn't malloc or calloc myStructArray so you shouldn't free it. Loop over the elements and free myStruct[i].array1 and array2
for(int i=0;i<16;i++)
{
free(myStruct[i].array1);
free(myStruct[i].array2);
}
The general rule is simple - free what you malloc/calloc/realloc/strdup/other allocs, nothing more or less. Note that alloca is an exemption - it allocates on stack, so you should never free what you got from it.
myStructArray myStruct[16];
myStruct is an array of objects created on stack. You can not call free on it. free needs to be called on resources acquired from free store ( using malloc, realloc etc., ). Instead you need call free on struct members array1, array2.

Redefining free memory function in C

I'm redefining memory functions in C and I wonder if this idea could work as implementation for the free() function:
typedef struct _mem_dictionary
{
void *addr;
size_t size;
} mem_dictionary;
mem_dictionary *dictionary = NULL; //array of memory dictionaries
int dictionary_ct = 0; //dictionary struct counter
void *malloc(size_t size)
{
void *return_ptr = (void *) sbrk(size);
if (dictionary == NULL)
dictionary = (void *) sbrk(1024 * sizeof(mem_dictionary));
dictionary[dictionary_ct].addr = return_ptr;
dictionary[dictionary_ct].size = size;
dictionary_ct++;
printf("malloc(): %p assigned memory\n",return_ptr);
return return_ptr;
}
void free(void *ptr)
{
size_t i;
int flag = 0;
for(i = 0; i < dictionary_ct ; i++){
if(dictionary[i].addr == ptr){
dictionary[i].addr=NULL;
dictionary[i].size = 0;
flag = 1;
break;
}
}
if(!flag){
printf("Remember to free!\n");
}
}
Thanks in advance!
No, it will not. The address you are "freeing" is effectively lost after such a call. How would you ever know that the particular chunk of memory is again available for allocation?
There has been a lot of research in this area, here is some overview - Fast Memory Allocation in Dr. Dobbs.
Edit 0:
You are wrong about sbrk(2) - it's not a "better malloc" and you cannot use it as such. That system call modifies end of process data segment.
Few things:
Where do you allocate the memory for the dictionary?
How do you allocate the memory that dictionary->addr is pointing at? Without having the code for your malloc it is not visible if your free would work.
Unless in your malloc function you're going through each and every memory address available to the process to check if it is not used by your dictionary, merely the assignment dictionary[i].addr=NULL would not "free" the memory, and definitely not keep it for reuse.
BTW, the printf function in your version of free would print Remember to free! when the user calls free on a pointer that is supposedly not allocated, right? Then why "remember to free"?
Edit:
So with that malloc function, no, your free does not free the memory. First of all, you're losing the address of the memory, so every time you call this malloc you're actually pushing the process break a little further, and never reuse freed memory locations. One way to solve this is to somehow keep track of locations that you have "freed" so that next time that malloc is called, you can check if you have enough available memory already allocated to the process, and then reuse those locations. Also, remember that sbrk is a wrapper around brk which is an expensive system call, you should optimize your malloc so that a big chunk of memory is requested from OS using sbrk and then just keep track of which part you're using, and which part is available.

Resources