3

I have the following structure that I've declared:

typedef struct binTreeNode
{
    void *data;
    struct binTreeNode *left;
    struct binTreeNode *right;  
} myBinaryTreeNode;

In my main function, I'm trying to use a pointer to an instance of that structure called root.

myBinaryTreeNode *root = malloc(sizeof(myBinaryTreeNode));
printf("\nPlease insert root data: ");
int input;
scanf("%d", &input);
root->data = (void*)&input;
printInt(root->data);
free(root); 

this code runs perfectly well. But, I thought that when you have a struct with members that are pointers, you should free() each one of them (additionally to the pointer to the struct).

So here, I didn't malloc for root->data (because I think that mallocing the struct does that), but it is initialized to the input value and it's value gets printed successfully. When I try to free(root->data) my program crashes.

So root->data is not malloced when I malloc root? If not, how can I still use it? Why does this happen? What am I missing here?

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
Ofer Arial
  • 1,129
  • 1
  • 10
  • 25
  • `So root->data is not malloced when I malloc root? If not, how can I still use it?` Just call another malloc on it. – Matt Mar 07 '17 at 10:57
  • Before you free something that you have a pointer to, you best make sure it's something you allocated. Did you allocated something and set the pointers in the structure to point at it? – StoryTeller - Unslander Monica Mar 07 '17 at 10:58

4 Answers4

4

First, get the concept of where and how you need to (or need not) call free().

You don't need to malloc() "for" root->data, that variable is already allocated while you allocated memory equal to the size of the structure. Now, next, you certainly need root->data to point to some valid memory, so that you can dereference the pointer to read from to write into it. You can do that by either of two ways

  • store an address which is valid (like in your case, supply the address of an already existing variable)
  • assign a pointer returned by another malloc() (success).

In case, you're storing the pointer returned by malloc(), yes you must free() the memory but in your case, root->data holds a pointer not returned by malloc(), so it does not need free()-in either.

Just to add and emphasis on the part related to free()-ing, you must not attempt to free() the memory which has not been previously allocated by a call to malloc() and family otherwise, it invokes undefined behavior. To quote, standard C11, chapter §7.22.3.3, (emphasis mine)

void free(void *ptr);

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

When I try to free(root->data) my program crashes.

You cannot free memory that you have not dynamically allocated. If you want to free the elements, you should first allocate them this way :

typedef struct binTreeNode
{
    int *data;
    struct binTreeNode *left;
    struct binTreeNode *right;  
} myBinaryTreeNode;

root->data = malloc(sizeof(int));
if (root->data == NULL)
{
    printf("Error allocating memory\n");
    return;
}
scanf("%d", root->data);
free(root->data);

Note that you should check the result of malloc before continuing.

So root->data is not malloced when I malloc root? If not, how can I still use it?

Note also that space for root->data is allocated when you allocate memory for the struct, but it is not malloced. You need an extra malloc especially for root->data, as shown in the example above. The reason why you need malloc for root->data is to be able to dereference the pointer.

Community
  • 1
  • 1
Marievi
  • 4,951
  • 1
  • 16
  • 33
1

data member points to input local variable, so you cannot free it.

You must free members if you dynamically allocate them, like

typedef struct binTreeNode
{
    int *data;
    struct binTreeNode *left;
    struct binTreeNode *right;  
} myBinaryTreeNode;

root->data = malloc(sizeof(int));
scanf("%d", root->data);
free(root->data);
paddy
  • 60,864
  • 6
  • 61
  • 103
LPs
  • 16,045
  • 8
  • 30
  • 61
  • Thanks for your answer! So how will `input` and alike memory will be freed eventually? And also, is one way better than the other? – Ofer Arial Mar 07 '17 at 11:08
  • `input`, as local scoped variable, has [automatic storage](https://en.wikipedia.org/wiki/Automatic_variable). – LPs Mar 07 '17 at 11:26
  • @OferArial `input` is a local variable. The associated object is automatically destroyed and the memory made available again when the program flow leaves the variable's scope (which may be the `main` function). Global variables are destroyed when the program exits. Dynamically allocated objects are never destroyed if they are not `free`d, although modern operating systems reclaim the memory from the program after the program has exited. But destructors are then never executed which may be bad for classes which hold more resources than just memory. – Peter - Reinstate Monica Mar 07 '17 at 11:27
  • @PeterA.Schneider thank you very much for the detailed information. So where are local variables saved in memory? On the stack? If not, who destroyes them? – Ofer Arial Mar 07 '17 at 11:54
  • Yes, on the stack. Only Olaf insists there is no stack, against all evidence ;-). But Olaf is correct insisting in that that doesn't matter; what matters is that the implementation guarantees to execute the objects' destructors upon leaving scope. That they are usually on the stack has the side effect that the memory gets overwritten when the stack is re-used (so that accessing local variables after the end of their lifetime is accessing re-purposed memory), and that indexing errors on the stack overwrite adjacent local variables. – Peter - Reinstate Monica Mar 07 '17 at 12:37
  • @PeterA.Schneider Can be stack, or register too. – LPs Mar 07 '17 at 12:57
  • 1
    @LPs Yes, true, but only as long as you don't look ;-). – Peter - Reinstate Monica Mar 07 '17 at 13:18
1

I have added some annotations to your code.

I hope this clears things up.

// I have added an enclosing block for the purpose of demonstration:
{
    // Here you allocate memory for a tree node object with dynamic/allocated 
    // storage duration.
    // That is: three pointers, that point to nowhere are created and will
    // exist until the memory holding them is free'd.
    myBinaryTreeNode *root = malloc(sizeof(myBinaryTreeNode));
    printf("\nPlease insert root data: ");
    // Here you create an object with automatic storage duration.
    // That is, the object is automatically destroyed when the function
    // returns or the block is closed: { ... }
    int input;
    // here you attempt to assign a value to the variable
    // (you should check the return value: the input may fail)
    scanf("%d", &input);
    // Here you assign the address of an object to a pointer.
    // Note that you are only allowed to use the pointer as long as the
    // object it points to "lives".
    root->data = (void*)&input;
    // Here you probably print the value, or the pointer address, or something else
    printInt(root->data);
    free(n); // <-- Where and how did you allocate this?
    // Here you free the memory holding the tree node
    free(root); 
} // <-- At this point the "input" variable is automatically destroyed.

You should really read up on the different storage durations (automatic and dynamic/allocated) and the purpose of dynamic memory allocation:


To address the questions in detail:

When I try to free(root->data) my program crashes.

That is because you can only free() what you have malloc(). Memory management is different for the different types of storage duration.

So root->data is not malloced when I malloc root?

Memory for the pointer is allocated, but it doesn't "own" or "point to" any object by default.

If not, how can I still use it?

Just as you did. You assign a memory address of an object to it, that lives long enough for you to use it. You can produce such object using dynamic memory management (then take care that you destroy it manually once you're done: don't leak memory) or using "automatic memory management" as you have done (then take care that it isn't destroyed too early: don't access invalid memory). (To name just two of the possible ways to create an object...)

Community
  • 1
  • 1
moooeeeep
  • 31,622
  • 22
  • 98
  • 187