5

I'm having trouble understanding some of the free() behavior.

int* ptr1 = (int*)malloc(sizeof (int)*10);
int* ptr2 = ptr1;
free(ptr2);

Is the free(ptr2) going to delete my array as I want ?

What if I do :

int** ptr1 = (int**)malloc(sizeof (int)*10);
int* ptr2 = (int*)malloc(sizeof (int));
*ptr2 = 10;
ptr1[0] = ptr2;
free(ptr1);

Is this code correct ? Will free(ptr1) will also delete the space of ptr2 ?

Thanks

Eli Korvigo
  • 10,265
  • 6
  • 47
  • 73
M-Gregoire
  • 808
  • 9
  • 22
  • In the first example, either one, but not both. The only information that you give to `free` is the pointer's value. In the second peculiar contrivance, only one memory space is returned to the system. – Weather Vane Apr 27 '16 at 16:08
  • 1
    there is a tool called `valgrind` that I suggest you look up and start using. It will show you any memory leaks in your program (if there are any). – Ryan Haining Apr 27 '16 at 16:08
  • 2
    Why is code using `sizeof(int)*10` to compute the memory needed for some pointers in `int** ptr1 = (int**)malloc(sizeof(int)*10);`. I'd expect `int** ptr1 = (int**)malloc(sizeof(int *)*10);` – chux - Reinstate Monica Apr 27 '16 at 16:11
  • 1
    Don't cast the return value of `malloc()`, see [here](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858#605858). – RastaJedi Apr 27 '16 at 18:33
  • 1
    [malloc()ing](https://makecleanandmake.com/2014/07/26/how-to-malloc-the-right-way/) – Ryan Haining Apr 28 '16 at 03:05

4 Answers4

5
int* ptr1 = (int*)malloc(sizeof(int)*10);
int* ptr2 = ptr1;
free(ptr2);

That is fine, ptr2 contains the same value as ptr1, and thus the memory you passed to malloc() is free()d.

int** ptr1 = (int**)malloc(sizeof(int)*10);
int* ptr2 = (int*)malloc(sizeof(int));
*ptr2=10;
ptr1[0]=ptr2;
free(ptr1);

That is not fine. You are storing the value of ptr2 in the ptr1 array, but not freeing it. You want:

int** ptr1 = (int**)malloc(sizeof(int*)*10);
int* ptr2 = (int*)malloc(sizeof(int));
*ptr2=10;
ptr1[0]=ptr2; 
...
free(ptr1[0]);
free(ptr1);

Note I have also changed the malloc() to allocate 10 pointers to int, not merely ten ints (which may not be the same size).

Finally note that you don't need to cast the return value from malloc() in C. I haven't fixed that for you as it is not a problem in itself and is unrelated to your question, but it is (arguably) bad style.

Community
  • 1
  • 1
abligh
  • 24,573
  • 4
  • 47
  • 84
  • Thanks ! If I define a struct with `int tab[10]` in it. Then create this struct with malloc and delete it with free. Should I worry about my tab ? – M-Gregoire Apr 27 '16 at 16:26
  • 1
    @Kenshin: If you allocate a `struct` will `malloc()` and free it with `free()` this will free the allocation you made with `malloc()` but not free anything referenced by the structure. The simple rule is for every allocation, there has to be a matched `free()` - nice and simple. There's no concept of a 'recursive' free. – abligh Apr 27 '16 at 16:28
  • Yes but my tab wasn't created with a malloc. So Is my tab considered part of my struct or should I delete it somehow ? – M-Gregoire Apr 27 '16 at 16:29
  • 1
    @Kenshin if you create the struct with `malloc()` but not the `int tab[10]` then you should only `free()` the `struct`, and not `free()` the `int tab[10]`. The rules are simple - match `malloc()` (and anything else that allocates on the heap) and `free()` – abligh Apr 27 '16 at 16:31
  • @Kenshin: in general it's useful to remember that C is quite stupid and does nothing 'behind your back'. Compare with (e.g.) Java. Some consider this to be a feature not a bug. – abligh Apr 27 '16 at 16:34
  • You're right that you don't need to cast `malloc()` return value, but it's not just that it's bad style if you do, it can hide errors (has to do with forgetting to include a header or something I think?). – RastaJedi Apr 28 '16 at 19:35
  • @RastaJedi click on the link I put in the text and it will lead you to a long discussion. – abligh Apr 28 '16 at 19:40
  • @abligh yeah that's a good link; I linked him to it in a comment in OP too. It's also good that it notes it's usually better to do `sizeof *array` instead of `sizeof (int)` in case the type changes. I never used to use this style until I read it here on SO. @Kenshin yeah and I know this only about C but the same can be said about C++: match every `malloc()`/`free()`, `new`/`delete`, and `new[]`/`delete[]`. – RastaJedi Apr 28 '16 at 19:43
4

Yes and no, respectively.

Also note that malloc(sizeof(int)*10); in the second example will work, but it will not necessarily allocate space for ten pointers.


To explain what happens in the first example, after the assignment to ptr2 you have something like this:

+------+
| ptr1 | ---\
+------+     \      +----------------------------+
              >---> | memory allocated by malloc |
+------+     /      +----------------------------+
| ptr2 | ---/
+------+

Both variables contain the same value, the pointer returned by malloc, so you can use either of them to access the allocated memory.

For the second question, what you have is something like this:

+---------+---------+---------+-----+
| ptr1[0] | ptr1[1] | ptr1[2] | ... |
+---------+---------+---------+-----+
  |
  |
  v
+----------------------------+
| memory allocated by malloc |
+----------------------------+
  ^
  |
  |
+------+
| ptr2 |
+------+

When you free the memory pointer to by ptr1 that only frees that memory, the memory pointed to by ptr2 is still there and accessible through ptr2.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

malloc and free do not know about your data structures. All they know about is blobs of bytes.

As a general rule, there should be a one-to-one relationship between your malloc and free calls. (There are plenty of exceptions, but it's a good general rule.)

It is never the case that a single call to free will simultaneously free two separate blocks allocated by two calls to malloc.

So, as others have said, the answers to your questions are "Yes" and "No".

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
0

Is the free(ptr2) going to delete my array as I want ?

I think the term delete cannot be used here. The GNU manual says :

When you no longer need a block that you got with malloc, use the function free to make the block available to be allocated again.

However free doesn't set pointer automatically to NULL because the function return type itself is void. Also,

Freeing a block alters the contents of the block. Do not expect to find any data (such as a pointer to the next block in a chain of blocks) in the block after freeing it.

I am not spurring a debate on whether you should set the pointer to NULL after freeing it. However,I felt tempted to post this example which crashes and burns :

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int* ptr1 = malloc(sizeof(int)*10);
    int* ptr2 = ptr1;
    free(ptr2);
    if(ptr2!=NULL)
    {
        printf("ptr is %p\n",ptr2); // still printf
        printf("Enter a number for ptr2 :");
        scanf("%d",ptr2);
        printf("Value pointed to by ptr2 : %d\n",*ptr2);
        printf("Value pointed to by ptr1 : %d\n",*ptr1);
    }
    else
        printf("Ptr2 pointed to null");
    printf("Size of ptr1 : %d\n",sizeof(ptr1));

    if(ptr1==NULL)
        printf("ptr1 NULL\n");
    printf("Enter a number for ptr1 :");
    scanf("%d",ptr1);
    printf("Value pointed to by ptr1 : %d\n",*ptr1);
    printf("Value pointed to by ptr2 : %d\n",*ptr2);

    free(ptr1);
    if(ptr1==NULL)
        printf("ptr1 freed\n");

    return 0;
}

Output

ptr is 0x1c92010
Enter a number for ptr2 :4
Value pointed to by ptr2 : 4
Value pointed to by ptr1 : 4
Size of ptr1 : 8
Enter a number for ptr1 :1
Value pointed to by ptr1 : 1
Value pointed to by ptr2 : 1
*** glibc detected *** ./testp: double free or corruption (fasttop): 0x0000000001c92010 ***
Segmentation fault (core dumped)
sjsam
  • 21,411
  • 5
  • 55
  • 102