Binary Search Tree - Memory Leak at insertion - c

I am trying to create a binary search tree and insert a new node in an iterative way. It is all working well except I am getting a memory leak in this function.
Valgrind says 7 blocks (I am adding 7 nodes) are missing.
I couldn't see where my leak is. I would appreciate another look at my code.
void bst_insert_node(bstree* bst, unsigned long phone, char *name) {
bst_node* current = bst->root;
bst_node* parent = NULL;
bst_node* new = (bst_node *)malloc(sizeof(bst_node));
new->phone = phone;
new->left = new->right = new->parent = NULL;
new->name = malloc(sizeof(char) * (strlen(name)+1));
strncpy(new->name,name,(strlen(name)+1));
while(current != NULL) {
parent = current;
if(phone < current->phone) {
current = current -> left;
}
else if(phone > current->phone) {
current = current -> right;
} else {
free(new);
printf("Diese Nummer ist schon bekannt \n");
return;
}
}
new->parent = parent;
if(parent == NULL) {
bst->root = new;
}
else if(new->phone < parent->phone) {
parent->left = new;
}
else {
parent->right = new;
}
}
Free methods:
void bst_free_subtree(bst_node* node) {
if (node == NULL) return;
bst_free_subtree(node->left);
bst_free_subtree(node->right);
printf("\n Deleting node: %lu \t %s", node->phone,node->name);
free(node);}
void bst_free_tree(bstree* bst) {
if(bst != NULL && bst->root != NULL) {
bst_free_subtree(bst->root);
bst->root = NULL;
}
}

As we all discussed in the comments, your memory leak is that you're not freeing the node->name strings that you have allocated. You need to add two more frees to your code:
in bst_insert_node, in the case where you can't insert the node, free(new->name) before you free(new)
in bst_free_subtree, free(node->name) before you free(node)
There is also an off-by-one error allocating space for a copied string, as in your answer. It might be simplest to just new->name = strdup(name) instead, which will do both the allocate and the copy in one go.
As an aside, if these are phone numbers then I'd probably store them as strings, not integers (or libphonenumber if you want to go the whole hog, but C++ not C) and if there's a problem inserting one then it might be better to return the error to the calling code (e.g. return true if inserted, false if not) and let that raise errors rather than printing from this code.

Related

C - sorting to list and memory leak

Hi I was deleting memory leaks in my code but I stucked in on moment.
Here I've got functions:
char* MakeLowerCase(char* word)
{
char* lower = (char *)malloc(sizeof(char)*strlen(word)+1);
strcpy(lower, word);
int i = 0;
for(i = 0; i < strlen(lower); i++){
lower[i] = tolower(lower[i]);
}
return lower;
}
void sortedInsert(Word** pH, Word* new_node)
{
Word* current;
/* Special case for the head end */
if (*pH == NULL || strcmp(MakeLowerCase((*pH)->word), MakeLowerCase(new_node->word)) == 1)
{
new_node->pNext = *pH;
*pH = new_node;
}
else
{
/* Locate the node before the point of insertion */
current = *pH;
while (current->pNext!=NULL &&
strcmp(MakeLowerCase(current->pNext->word), MakeLowerCase(new_node->word)) == -1)
{
current = current->pNext;
}
new_node->pNext = current->pNext;
current->pNext = new_node;
}
}
After using these functions my whole list was sorted. But to avoid memory leaks from MakeLowerCase I tried to so something like this:
void sortedInsert(Word** pH, Word* new_node)
{
Word* current;
/* Special case for the head end */
if(*pH = NULL)
{
*pH = new_node;
return ;
}
char* word1 = MakeLowerCase((*pH)->word);
char* word2 = MakeLowerCase(new_node->word);
if (*pH == NULL || strcmp(word1, word2) == 1)
{
new_node->pNext = *pH;
*pH = new_node;
}
else
{
/* Locate the node before the point of insertion */
current = *pH;
char* word3 = MakeLowerCase(current->pNext->word);
char* word4 = MakeLowerCase(new_node->word);
while (current->pNext!=NULL && strcmp(word3, word4) == -1)
{
current = current->pNext;
}
new_node->pNext = current->pNext;
current->pNext = new_node;
}
free(word1);
free(word2);
}
After changes my list isn't sorted as earlier (just a part of it is sorted in weird way). What did I wrong?
As you already noticed, the original approach leaks memory. The returned memory from MakeLowerCase() was never freed. In your second attempt you tried to fix this but leaked now word3 and word4. You fixed that later.
The main error is that in your revised function you have a loop advancing current while comparing word3 against the new item. You missed to update word3 inside the loop after advancing current. And You have to free it too.
As mentioned in my comment you should simply use stricmp(), the ignore-case brother of strcmp, so you don't need MakeLowerCase() with all the leaks.
Here my short code. With linked lists I love to use double indirection like Word** because it reduces the number of edge cases and by thus the number of conditional instructions.
void sortedInsert(Word** pHead, Word* new_node)
{
//*pHead is a possible insertion point for new_node, like *pHead=new_node
while (*pHead)
{
if (stricmp(new_node->word, (*pHead)->word) < 0)
break; //Insertion point found.
pHead = &(*pHead)->pNext;
}
//*pHead is the insertion point for new_node, the remaining list at *pHead goes behind us
new_node->pNext = *pHead;
*pHead = new_node;
}

Printing binary search tree, segmentation fault error 11

could you help me?
Program reads words from a file and puts them into binary search tree, but I get "Segmentation fault: 11" when running my print function.
struct node {
char * item;
struct node * left;
struct node * right;
};
struct node * new(char * a) {
struct node * new;
new = (struct node *)malloc(sizeof(struct node *));
new->item = a;
new->left = new->right = NULL;
return new;
}
struct node * insert(struct node * a, char * b) {
if(a == NULL) {
a = new(b);
}
else if (b <= a->item) {
a->left = insert(a->left, b);
}
else {
a->right = insert(a->right, b);
}
return a;
}
void print(struct node * a) {
if (a->left == NULL && a->right == NULL)
printf("%s", a->item);
else if (a->left != NULL)
print(a->left);
else
print(a->right);
}
from main.c :
struct node * root = NULL;
struct node * start;
start = root;
while (fscanf(fp, "%s", temp) != EOF) {
root = insert(root, temp); // insert function works ok
}
print(start);
UPDATE:
I've made a change in main.c:
int i = 0;
while (fscanf(fp, "%s", temp) != EOF) {
root = insert(root, temp);
if (!i) {
start = root;
i = 1;
}
}
Now it doesn't show error, but it prints only the last word from the tree instead of printing it recursively. Any suggestions?
UPDATE #2:
Thank you for your help. Following your suggestions I've made changes to this function:
struct node * new(char * a) {
struct node * new;
char * stringcopy;
stringcopy = malloc(strlen(a) + 1);
strcpy(stringcopy, a);
new = malloc(sizeof(* new));
new->item = stringcopy;
new->left = new->right = NULL;
return new;
}
Now everything works fine.
The original problem was almost certainly that start was NULL since you did not update it when you updated root. (Meanwhile it seems that the whole start is unnecessary; just use root directly.)
The new problem (printing only the last word) is that you are not traversing the tree correctly: your print function only prints if both left and right are NULL, so only a leaf node is ever printed, and furthermore it does not descend into the right branch if there is a left branch.
You could try something like this instead (untested code):
void print(struct node * a) {
if (a == NULL) { return; }
print(a->left);
(void) puts(a->item);
print(a->right);
}
In particular, note that if you are at a non-NULL node, you need to print its item unconditionally, or the complete output will be missing that node.
Another problem seems to be that you are not copying item when you create the node. So if your temp in insert(root, temp) is indeed a temporary object that will be overwritten or freed, all of your items (except possibly the last) will be invalid by the time you try to print them. Instead of assigning new->item = a, do the equivalent of new->item = strdup(a) and then remember to free it when you free the node.
(strdup is not in the C standard library, but it is easy to implement: allocate enough space for the string, including NUL terminator, and copy.)
Also, the comparison b <= a->item is almost certainly not doing what you expect it to; see strcmp.

"A heap has been corrupted" after using malloc twice

I have a linked list of "words" that I'm trying to build, I made a function called "add_to_mem" which adds to the linked list the next word.
I've made a couple of checks on the code, and found out that he works twice - once when the linked list is a NULL, and once when it's not - and it is does working, but in the third time I'm calling to the method - I'm getting an "A heap has been corrupted" error.
The code:
typedef struct { unsigned int val : 14; } word;
typedef struct machine_m
{
word * current;
int line_in_memo;
char * sign_name;
struct machine_m * next_line;
}Machine_Memo;
The function:
/*Adding a word to the memory.*/
void add_to_mem(word * wrd, int line, char * sign_name)
{
Machine_Memo * temp = NULL, *next = NULL;
if (machine_code == NULL)
{
machine_code = (Machine_Memo *)malloc(sizeof(Machine_Memo));
if (machine_code == NULL)
{
printf("Memory allocation has failed.");
exit(1);
}
machine_code->current = wrd;
machine_code->line_in_memo = line;
machine_code->sign_name = sign_name;
machine_code->next_line = NULL;
}
else
{
printf("token has been reached");
temp = machine_code;
next = (Machine_Memo *)malloc(sizeof(Machine_Memo)); //Line of error
if (next == NULL)
{
printf("MEMORY ALLOCATION HAS FAILED. EXITING PROGRAM.\nThe problem has occured on code line %d", 775);
exit(0);
}
next->current = wrd;
next->line_in_memo = line;
next->sign_name = sign_name;
next->next_line = NULL;
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next;
}
}
}
As far as I understand the code, it does not create a linked list. it creates nodes, but does not link them together.
at first call, the machine_code (head of list) is created.
at next call, the node 'next' is created, however, the loop:
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next;
}
does nothing as the 'machine_code->next' value is null. so code inside the loop is not executed. and we do not get here a linked list, but sporadic nodes not connected each to other.
you may wanted (as pointed at the other post here) to have something like:
while (temp->next_line != NULL)
{
temp = temp->next_line;
}
temp->next_line = next;
Here
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next; // move out of the loop
}
you may want to move the last assignment outside of the loop.

C Quicksort (linked list) segmentation fault

I have to create a quicksort on a linked list (in C).
I have my first and last pointer an the pivot (in this code it's the first element of the list).
The structs I have to use:
typedef struct list_element list_element;
struct list_element {
char *password;
int count;
list_element* next;
};
typedef struct list list;
struct list {
list_element* first;
list_element* last;
};
I have a file with 100 passwords and counts.
Like this:
password1 123 (next line) password2 435 (next line) password3 133 ...
The passwords have to be sorted (according to their count) in the end of this programm.
There isn't needed any extra memory allociation for the left and right lists because I only have to use the next pointers. (That's what the hint in the exercise says.)
The given main-function:
int main(int argc, char** args)
{
if (argc != 2)
{
printf("Nutzung: %s <Dateiname>\n",args[0]);
return 1;
}
list mylist;
init_list(&mylist);
read_data(args[1],&mylist);
qsort_list(&mylist);
printf("Sortierte Liste:\n");
print_list(&mylist);
free_list(&mylist);
return 0;
}
I have initialized my list:
void init_list(list* mylist)
{
mylist->first = NULL;
mylist->last = NULL;
}
And insert a new element at end (passwort = passwords in file, hauefigkeit = counts in file):
void insert_list(list_element* le, list* mylist)
{
if (mylist->first != NULL) {
le->next = mylist->last;
mylist->last = le;
le->next= NULL;
}
else {
mylist->last->next = le;
mylist->last = le;
mylist->last->next = NULL;
}
}
Read data from file:
void read_data(char* filename, list* mylist)
{
FILE *file_in = fopen(filename, "r");
if (file_in == NULL) {
perror("Could not open input file!");
exit(1);
}
char buffer[999] = "0";
char *passwort = (char*) calloc(1,sizeof(passwort));
int haeufigkeit = 0;
while (fgets(buffer, sizeof(buffer), file_in) != NULL) {
sscanf(buffer, "%s %d", passwort, &haeufigkeit);
list_element* le = (list_element*)calloc(1,sizeof(list_element));
for(int i = 0; i <=100; i++) {
le->password[i] = passwort[i];
}
le->count = haeufigkeit;
le->next = NULL;
insert_list(le, mylist);
}
fclose(file_in);
}
Partition of the list:
list_element* partition( list* input, list* left, list* right )
{
list_element* pivot = NULL;
if (input->first != NULL) {
list_element* temp;
pivot = input->first;
input->first = input->first->next;
pivot->next = NULL;
left->first = NULL;
right->first = NULL;
while (input->first != NULL) {
if((pivot->count)>(input->first->count)){
temp=input->first->next;
insert_list(input->first, left);
input->first=temp;
}
else {
temp = input->first->next;
insert_list(input->first, right);
input->first = temp;
}
}
}
return pivot;
}
The actual quicksort:
void qsort_list(list* mylist)
{
if(mylist->first == mylist->last){
}
else{
list* left = calloc(1,sizeof(list));
list* right= calloc(1,sizeof(list));
list_element* pivot = partition(mylist, left, right);
qsort_list(left);
qsort_list(right);
if(left->first == NULL){
mylist->first = pivot;
}
else{
mylist->first = left->first;
left->last->next = pivot;
}
if(right->first == NULL){
pivot->next = NULL;
mylist->last = pivot;
}
else{
pivot->next = right->first;
mylist->last = right->last;
}
free(right);
free(left);
}
}
In the end print list:
void print_list(list* mylist)
{
list_element *elem = mylist->first;
while (elem != NULL) {
printf("%s %d\n", elem->password, elem->count);
elem = elem->next;
}
}
And free list:
void free_list(list* mylist)
{
list_element *current;
list_element *second;
current = mylist->first;
while (current != NULL) {
second = current->next;
free(current);
current = second;
}
}
Syntax should be ok. GCC (c99, Wall) compiles without any problems.
But there is an segmentation fault. I have been searching for hours now and I have no idea where the problem could be. Maybe you can help me with this problem.
After the first two answers there isn't any segmentation fault. But still have a problem with read_data function.
The program can't read the passworts correctly. Maybe i misunderstood you answers in relation to the read function.
That's the current function:
void read_data(char* filename, list* mylist)
{
FILE *file_in = fopen(filename, "r");
if (file_in == NULL) {
perror("Could not open input file!");
exit(1);
}
char buffer[999] = "0";
int haeufigkeit = 0;
while (fgets(buffer, sizeof(buffer), file_in) != NULL) {
char passwort[100];
sscanf(buffer, "%s %d", passwort, &haeufigkeit);
list_element* le = (list_element*)
calloc(1,sizeof(list_element));
le->password = passwort;
le->count = haeufigkeit;
le->next = NULL;
insert_list(le, mylist);
}
fclose(file_in);
}
As Leonardo Alves Machado pointed out, the first reflex when having trouble with a C/C++ program is to run it with a debugger like gdb. Here is the basics:
gcc -g main.c -o main
gdb main
(gdb) run
Note the -g compilation flag: this will add debug information to the executable.
In read_data, the lines
for(int i = 0; i <=100; i++) {
le->password[i] = passwort[i];
}
really bug me. You allocate space for passwort (which you never free by the way) and try to copy it to le->password, which is a simple pointer (no allocated space). What you actually need is to make le->password point to passwort, i.e.
le->password = passwort;
In free_list, don't forget to deallocate the passwort space before deallocating the list_element space with:
while (current != NULL) {
second = current->next;
free(current->password);
free(current);
current = second;
}
One of the first issues your program encounters is that read_data() does not allocate enough space for passwort. It's unclear, actually, why you are dynamically allocating this at all, but given that you are doing so, sizeof(passwort) is the size of one pointer to char (since that's what passwort is) -- probably either 4 or 8 bytes. Later, you seem to assume that the allocated space is 100 bytes long when you (attempt to) copy its contents into a list element. Why not simply declare it as a 100-char array?
char passwort[100];
Indeed, if you also declare list_element.passwort the same way then your password-copying code inside the loop will be correct, albeit a bit non-idiomatic.
As it is, that code is problematic, as #Derlin observes. His proposed solution is incorrect, however; you must not make the list elements point to the local passwort as long as that is allocated only once for the whole routine. Then all list elements will have the same password string, which is not what you want. If you want your list elements to contain pointers to the passwords, as they do now, then you'll want to move the declaration and allocation of passwort inside the loop, so that you get separate password space allocated for each list element. Then the suggestion to assign le->password = passwort would be correct.
Another early issue is that your insert_list() function is badly broken.
Consider first what happens when you try to insert an element into an empty list, as initialized by init_list(). The list's next and last members will both be null, and insert_list() will therefore attempt to execute this code:
mylist->last->next = le;
mylist->last = le;
mylist->last->next = NULL;
Observe that mylist->last is null, therefore the first line invokes undefined behavior by attempting to dereference a null pointer. A segmentation fault is an eminently plausible observed result. You might fix that by changing the first of those lines to
mylist->next = le;
Now consider what happens when you try to insert into a non-empty list. In that case, you execute these lines:
le->next = mylist->last;
mylist->last = le;
le->next= NULL;
Since your intention is to insert the new element at the end (i.e. to append it), it is odd that you set the new element's next pointer to the list's last element. It is especially odd that you later overwrite that value with NULL. You seem to have it backward: you want to set the initial last element to point to the new element as its next element, not the other way around:
mylist->last->next = le;
Indeed, that's exactly the code that was wrong for the empty-list case, but it's fine when the list is non-empty.
Overall, your function also suffers from an odd lack of parallelism and some hidden code duplication. I'd probably write the overall function something more like this:
void append_to_list(list_element* le, list* mylist)
{
le->next= NULL;
if (mylist->first != NULL) {
mylist->last->next = le;
mylist->last = le;
}
else {
mylist->first = le;
mylist->last = le;
}
}

linked list delete function

The following code snippet is not working right.
void deleteNode(list **start, int pos) {
int currentPosition=0;
list *currentNode;
list *nodToDelete;
currentNode = *start;
if (currentNode == NULL) {
printf("Empty List\n");
} else if (pos == 0 ) {
nodToDelete = *start;
*start = nodToDelete->next;
free(nodToDelete);
} else {
while (currentNode->next != NULL) {
if (currentPosition >= pos -1) {
break;
}
currentPosition++;
currentNode = currentNode->next;
}
if (currentPosition < pos -1 || currentNode->next == NULL) {
printf("No node at given position exists\n");
} else {
nodToDelete = currentNode->next;
currentNode = nodToDelete->next;
free(nodToDelete);
nodToDelete = NULL;
}
}
}
void displayList(list *node) {
if (node == NULL) {
printf("Empty List");
}
while (node != NULL) {
printf("%d\t", node->data);
node = node->next;
}
printf("\n");
}
int main()
{
list *start, *node;
start = NULL;
insertNode(&start, 2);
insertNode(&start, 3);
insertNode(&start, 4);
insertNode(&start, 1);
insertNode(&start, 5);
deleteNode(&start, 3);
displayList(start);
}
When executed the output is
Before Deletion 2 3 4 1 5
After Deletion 2 3 4 0 5
It is supposed to delete 1 but it is inserting 0 at its place.
Here is something that might work --
Replace
currentNode = nodToDelete->next;
with
currentNode->next = nodToDelete->next;
You basically need the node before the nodetodelete to have its next to point to the node that nodetodelete used to point to
Once you've found the node you want to take out of the list, you need to actually take it out. =)
...
nodToDelete = currentNode->next;
currentNode->next = nodToDelete->next;
free(nodToDelete);
...
Besides the problem with currentNode->next = nodToDelete->next; and negative positions you are mixing your ui and your logic. As much as possible you should separate the two.
Sending something to the ui is a way of reporting progress; whether the ui is a command line, a browser or a speaker. Within deleteNode, an empty list or a position that is out of bounds, is not progress. Sequentially both are the same as success - you are done. If you want failure to be to be reported, that should be done where it can lead to a separate sequence...i.e the caller. Also, by mixing in ui, you introduce an unnecessary dependency and failure (what if there's a bug in printf, YOUR function will crash when it doesn't doesn't have to). If you're function returns a defined result, the caller can decide if/how to report that result, including success (your function currently doesn't do so, and the caller has no way telling the difference between sucess or failure).

Resources