1

I am learning C and I am playing with malloc and free. But for some reason when I use free() in the main everything works but when I put it in my function it does not

  #include <stdlib.h>
  #include <stdio.h>

  struct st {
    int number;
  };
  void del(struct st *s) {
    if (s == NULL) return;
    free(s); s = NULL;
  }
  int main() {
    struct st *s;
    s = (struct st *)malloc(sizeof(struct st));
    s->number = 4;
    printf("The value is: %d", s->number);
    del(s);
  //  free(s); s= NULL;
    if(s == NULL) printf("\nThe struct is removed from memory\n");
    else printf("\nThe value is: %d\n", s->number);
    return 0;
  }

This echo:

The value is: 4
The value is: 0

But if I do:

   // del(s);
    free(s); s= NULL;

it works

Pat R Ellery
  • 1,696
  • 3
  • 22
  • 40
  • Why this is a duplicate? – Pat R Ellery May 14 '15 at 15:37
  • 3
    This is not really a duplicate of that question. The main issue here is that parameters are passed by copy, and so `s = NULL;` inside `del()` only changes the local copy (the change is not propagated back to `main()`). The `free()` is working. – Filipe Gonçalves May 14 '15 at 15:38
  • So, you can call `del(s)` in `main()`, and then, in `main()`, write `s = NULL;`. – Filipe Gonçalves May 14 '15 at 15:38
  • @FilipeGonçalves how can I use my function to free and NULL it then? – Pat R Ellery May 14 '15 at 15:43
  • Not a duplicate. @FilipeGonçalves has the answer. If you really wanted to free and mark a pointer null inside a function, you would have to declare as `del(struct st** s)` and `free(*s);*s=NULL;`. Then you would need to call as `del(&s);` – AShelly May 14 '15 at 15:44
  • 1
    Pass a pointer to the pointer: `void del(struct st **s) { free(*s); *s = NULL; }` and then call it in `main()` like this: `del(&s);` – Filipe Gonçalves May 14 '15 at 15:45
  • Think about the fact that if you declared your version of del as `void del(struct st* p){free(p);p=NULL;}` you would have gotten identical compiler output, and it should be clearer why it doesn't work. The fact that the argument is named the same doesn't make it the same. – AShelly May 14 '15 at 15:49

2 Answers2

2

You are passing the pointer to your function, which means it only has access to the local copy of this pointer. So your free(s) will free only this local copy. If you want to free a variable, that is outside of the scope of the function from which you call free, you need to gain access to it by derefering again (passing a pointer to this pointer).

void del(struct st **s) {
    if (*s == NULL) return;
    free(*s); 
    *s = NULL;
}

should work fine.

Edit: call the function by del(&s);

Michał Szydłowski
  • 3,261
  • 5
  • 33
  • 55
0

Your del function frees the allocated memory and assigns NULL to the local copy of the variable. However, the local copy is not the same copy as that at the call-site (even if both point to the same allocated object, that has been freed).

You then end up doing what's called "use after free()", which is (probably) not actively harmful in this specific case, but can be a crash bug in the general case (and possibly a vector for code injection and exploits).

Either re-write del to take a pointer to a pointer and pass &s in, or have del return "the new value" and do s = del(s).

Vatine
  • 20,782
  • 4
  • 54
  • 70