7

Why would freeing a pointer say p, which is assigned to where another pointer q points to, free q as well?

//for example,
int *p = malloc(sizeof(int));
*p = 10;
int *q = malloc(sizeof(int));
q = p;
free(p);
//This frees q as well.

Pointers q and p have different addresses but only point to the same location (i.e. to say that they store the same address which is of 10. Correct me if I'm mistaken there).

The contradiction most definitely arises in the way I think about pointers or in the way free() works because from all that I know (which is not a lot), since q and p have different addresses, freeing p should not affect q at all, unless I am wrong in understanding pointers, or that free()/memory works in a peculiar way.

I'd like to know why this is so. (I'm aware of the post Free an assigned pointer, but it doesn't explain why or how exactly this happens)

Cowgirl
  • 97
  • 5
  • Because of `q = p;`. The memory once assigned to `q` has "leaked". – trojanfoe Oct 13 '19 at 09:11
  • @trojanfoe, ```q=p;``` assigns the value of p (which is also the address of 10 say 00A1500) to q, right? So if p and q were boxes, their values would be 00A1500, but their addresses would still be different. – Cowgirl Oct 13 '19 at 09:16
  • @Cowgirl — yes, both `p` and `q` would contain the same pointer value, but the memory originally allocated to `q` is lost by the assignment `q = p;`. When you call `free(p);`, it is the value in `p` — 0x00A1500 in your hypothetical — that is passed to `free()`, not the address of `p`; it is the same as if you called `free(q)`. You're right — `&p != &q`, but what's at issue is the value stored in those two separate addresses, and because of the `q = p;` assignment, the same value is stored in both. – Jonathan Leffler Oct 13 '19 at 09:50
  • If I write ```int x = 10; p=&x; q=p; free(p);```, ```printf("%d",*p);``` and ```printf("%d",*q);``` give a valid output (10). – Cowgirl Oct 13 '19 at 10:37
  • regarding: `int *q = malloc(sizeof(int)); q = p;` the result is the returned value from `malloc()` for `q` will be overlayed. the result is an unrecoverable memory leak – user3629249 Oct 14 '19 at 05:14

2 Answers2

7

After

int *p = malloc(sizeof(int));
              x
            +----+
p --------> |    |
            +----+

P is pointing to some x memory which holds the some junk data.

*p = 10;

You are putting 10 into x

              x
            +----+
p --------> | 10 |
            +----+

With below

int *q = malloc(sizeof(int));
              y
            +----+
q ------->  |    |
            +----+

You created one more memory y to which q is pointing.

When you assign

q = p;
              x
            +----+
p --------> | 10 |
q --------> +----+

              y
            +----+
Memory leak |    |
            +----+

You made q to point x memory as well, losing the only reference to y memory.

With freeing p

free(p);



p -------->  (invalidated)
q --------> 

              y
            +----+
Memory leak |    |
            +----+

You deleted x memory thus p and q are pointing to freed memory.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
kiran Biradar
  • 12,700
  • 3
  • 19
  • 44
  • That makes sense. But if I write ```int x = 10; p=&x; q=p; free(p)```, de-referencing p and q still gives 10. How would that be if I just freed p? – Cowgirl Oct 13 '19 at 10:25
  • 3
    That's undefined behaviour. `free()` does not concern itself with memory-ownership, just management. So, maybe you can still access the memory and it has not been overwritten - maybe you get a segfault. You just can't know. – 3ch0 Oct 13 '19 at 11:59
4

Perhaps this would help:

You are not freeing p or q themselves. You are freeing the memory block pointed to by them.

After free(), both p and q themselves continue to exist. You can no longer dereference them, but you can continue using them in other ways. For example, you can make them point to another, valid, address (after which it will again become permissible to dereference them).

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Even so, I am only freeing p and not q. – Cowgirl Oct 13 '19 at 09:20
  • I'm sorry, I understand your point now. But if I write ```int x = 10; p=&x; q=p; free(p);```, ```printf("%d",*p);``` and ```printf("%d",*q);``` still give a valid output (10). – Cowgirl Oct 13 '19 at 10:40
  • @Cowgirl As @3ch0 said above, that's undefined behavior. It's working because the same bits happened to still be stored at the former address of `p` (freeing doesn't clear memory). But at this point that was no longer a guarantee. Had you done other allocations since freeing `p`, even if you had done nothing extra with `p` and `q` themselves, the program would have been allowed to reuse the now freed memory and might have filled the bits with other values. Now, the output of your print statements would change (unless the new bits stored there just happened to be the same as the bits for a 10). – SO Stinks Jun 02 '21 at 22:57