2

Essentially, I have created a piece of Code which consists of a tree, whereby each tree node has its own linked list containing data, (each treeNode containing data as well). So that each treeNode can have multiple data items for that specific treeNode.

For this structure therefore to be created, I calloc a treenode, pass the address of that treenode to a createListNode function, and calloc a ListNode. My confusion stems really from, where exactly should I be freeing memory? Merely at the end of the program before return 0; in main, or elsewhere. Baring in mind once all the input is added to the tree and list, it then asks the user for a name, and displays the linked list of data appropriate for that name.

Cheers.

T.C.

EDIT:

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

typedef struct ListNode {
    char            *number;
    struct ListNode *next;
}ListNode;

typedef struct TreeNode {
    char            *name;
    ListNode        *numbers;
    struct TreeNode *left;
    struct TreeNode *right;
}TreeNode;

TreeNode* AddNode(TreeNode *, char *, char *);
void  AddNum(TreeNode *, char *);
void N_Print(TreeNode* root);
TreeNode* SearchTree(TreeNode* root, char *search);

int main(void) {
char my_string[50], name[25], number[25];
TreeNode *root = NULL;
while ((fgets(my_string, 50, stdin)) != NULL) {
        if (my_string[0] == '.')
            break;      
    sscanf(my_string, "%s %s", name, number); 
    root = AddNode(root, name, number);  
}   
N_Print(root);
free(root);
free(root->numbers);
return 0;
}

TreeNode* AddNode(TreeNode *root, char *name, char *number) {
int comparison;   
if (root == NULL) {
    root = (TreeNode*)calloc(1,sizeof(TreeNode));
    root->name = strdup(name); 
    root->left = root->right = NULL;      
    AddNum(root, number);
}else if ((comparison = strcasecmp(name, root->name)) < 0)
    root->left = AddNode(root->left, name, number);
else if ((comparison = strcasecmp(name, root->name)) > 0) {
    root->right = AddNode(root->right, name, number);
} else if ((comparison = strcasecmp(name, root->name)) == 0 ) {
    AddNum(root, number);
}       
return root;
}

void AddNum(TreeNode *tn, char *number) {
 ListNode *ln = (ListNode *)calloc(1, sizeof(ListNode));
 ln->number = strdup(number);
 ln->next = tn->numbers;
 tn->numbers = ln;
}

TreeNode* SearchTree(TreeNode* root, char *search) {
int comparison;
if (root == NULL) {
    return NULL;
} else if ((comparison = strcasecmp(search, root->name)) == 0) {
    return root;
} else if ((comparison = strcasecmp(search, root->name)) < 0) {
     return SearchTree(root->left, search);
} else if ((comparison = strcasecmp(search, root->name)) > 0) 
     return SearchTree(root->right, search);    
}

void N_Print(TreeNode* root) {
TreeNode* search_val;
char search[25];
while(1) {
    printf("Type a name please: ");
    scanf("%24s", search);
            if (search[0] == '.')
                    break;
    search_val = SearchTree(root, search); 
    if (search_val == NULL) {
        printf("NOT FOUND\n");
        continue;
    }
    ListNode* ln = search_val->numbers;
    while ( ln != NULL) {
            printf("%s\n", ln->number);
            ln = ln->next;
    }
}
}
PnP
  • 3,133
  • 17
  • 62
  • 95

7 Answers7

4

You should free the memory when it is no longer needed. That of course depends on your application's needs.

In garbage collected environments (e.g. Java) the garbage collector frees memory when nothing is pointing at it. Following that as a starting point, you want to be sure to free memory before you remove your references to it.

David V
  • 11,531
  • 5
  • 42
  • 66
3

The best plan (IMO) is to free memory at the point where you don't need to access it any more. however if you only use a small amount of dynamically allocated memory it probably wont make much of a difference if you do it all at the end of your program (assuming you keep track of it all)

smitec
  • 3,049
  • 1
  • 16
  • 12
2

It's simple:

You free the memory when you have no more need for it. In your case, it seems you'll never have to remove a node so don't worry about deleting any. It is automatically freed when your program exits. Be careful though, you should delete all memory which all of its pointers that reference it get out of scope, making it unusable. This may cause memory leaks.

slartibartfast
  • 4,348
  • 5
  • 31
  • 46
2

When you no longer need the resources acquired from free store. So, it depends on what point you are not using calloc resources, you can start free it. But beware of dangling references.

Mahesh
  • 34,573
  • 20
  • 89
  • 115
2

You can free all the data as soon as you don't need it anymore, like when you're done printing it. In your case, if this is all what you program do it does not really matter as your kernel will free all memory allocated by your program at termination. However it matters if the program keeps running as it means you eating memory that cannot be used for other programs.

It's a bit like with previous version of firefox where it did not release memory after closing a tab. The program kept asking for more and more memory without releasing it.

Quentin Casasnovas
  • 1,079
  • 5
  • 10
2

You free the memory, once you have no use for it anymore. If that happens before program exit, well you free it before return. If the program wants to continue on whatever and you don't have need for the tree anymore, you free it and the continue with the program.

If for example the linked lists in the tree could at some stage shrink, the no-more-used nodes should be immediately freed.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
0

As everyone above says, free it whe you don't need it anymore, but additionally it is often a good idea to try to free on the same level that you create. This is more complicated when you are passing references around and such.

Irony
  • 317
  • 1
  • 3
  • 11