1

I'm pretty much new to C and i have a question about allocating memory. So I tried this code below that should free the structure elem1.

struct elem{

    char *data1;
    char *data2;

};

int main()
{

    struct elem *elem1 = malloc(sizeof(struct elem));
    elem1->data1 = "abc";
    elem1->data2 = "def";
    char *a = elem1->data1;
    char *b = elem1->data2;
    free(elem1);

    printf("%s\n%s\n",a,b);
    return 0;
}

The code compiles just fine and it gives back,

abc 
def

I expected it to fail since free should also free the memory of its members. But why does it work? And what should I do if I want to access the members of the structure after I free the structure?

  • What do you mean by "fail"? – melpomene May 01 '19 at 13:47
  • 2
    There is a difference between a pointer and the data to which it points, and it is crucial that you understand it. Freeing the memory in which a pointer is stored, such as the memory of the members of an instance of your structure, has no effect on data to which that pointer points. – John Bollinger May 01 '19 at 13:54
  • 1
    Notice that the code does **not** access any members **after** call of `free`! You only access `a` and `b` which contains a **copy** of the member values **before** the `free`. It's perfectly valid code. – Support Ukraine May 01 '19 at 13:54
  • 2
    You're allocating into `elem1` then using `node`. I assume you meant to use `elem1` throughout. – pmg May 01 '19 at 13:55
  • 2
    @Downvoters: This question is well written, compiles, runs, and the OP has taken the time to document the actual and expected behaviour, and it's not of the "this is ub get over it" ilk. Hence my upvote (and answer). – Bathsheba May 01 '19 at 13:56
  • 1
    @pmg yes sorry it was a mistake. I have edited it. – Fareza Aditya H May 01 '19 at 14:13
  • @Bathsheba No, the expected behavior is missing from the question. – melpomene May 01 '19 at 14:16
  • After freeing make `elem1` to point to `NULL` and do proper error handling i.e if `elem1` is not `NULL` then only allow to access `elem1->data1`. – Achal May 01 '19 at 14:19
  • Yes, the members of that particular structure are also freed. – Mr. Suklav Ghosh May 01 '19 at 15:09

2 Answers2

9

The members are part of the structure. Freeing the structure deallocates all of its members.

However, in your example, the members are just pointers. You're copying a pointer into the structure (node->data1 = ...), then out of the structure (... = node->data1), then freeing the structure. None of this affects the memory that the pointer is pointing to.

In your example the actual strings are stored in static memory (they're string literals). That means they're never destroyed; they live as long as the program is running. That's why it's perfectly safe to print them. Your code is fine.

Finally, accessing freed memory has undefined behavior (meaning anything can happen, including a program crash or appearing to work correctly). If you want to access members of a structure that has been freed, just do that:

struct elem *p = malloc(sizeof *p);
free(p);
p->data1 = "boom!";  // Undefined behavior!

However, that would be a bug, so ... don't, please.

melpomene
  • 84,125
  • 8
  • 85
  • 148
7

Every malloc has to be balanced with a corresponding free.

Your assignment node->data1 = "abc"; assigns a pointer to the read-only literal "abc", so there is no dynamic memory here, and therefore you must not use a free.

In your particular case, you are able to retain that pointer a having called free on the struct since you did not have to free that memory and it didn't ever belong to the struct. But that does not work in general: if you had used malloc to set node->data1 then (1) you would have to call free on that pointer before you attempt to call free on the struct, and (2) the behaviour of a subsequent deference of node->data1 would be undefined.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483