I can't seem for the life of me figure out what the is wrong with my code in the deletion of a whole BST.
I figure since there doesn't seem to be a problem with this:
void emptyTree(BST **root){
if((*root)!=NULL){
emptyTree(&(*root)->left);
emptyTree(&(*root)->right);
free(*root);
}
}
Then the whole problem lies with the initial entry of each node in the tree. Can anyone point out what's wrong here?
void insertNode(BST **root, BST *temp){
if((*root)!=NULL){
temp->parent = *root;
if(((*root)->value) < (temp->value))
insertNode(&(*root)->right,temp);
else if(((*root)->value) > (temp->value))
insertNode(&(*root)->left,temp);
else if(((*root)->value) == (temp->value)){
printf("The number %i is already in the tree.\n",temp->value);
return;
}
} else {
*root = temp;
printf("%i was added to the tree.\n",temp->value);
return;
}
}
void newNode(BST **root, int x){
BST *newnode;
newnode = (BST *)malloc(sizeof(BST));
newnode->value = x;
newnode->left = newnode->right = newnode->parent = NULL;
insertNode(root,newnode);
}
It compiles, it runs, it does absolutely every function right(including one that deletes one node at a time). Except the 'Delete All'(emptyTree) one. It doesn't delete everything(?). It doesn't even show an error when I run through the emptyTree function. It only errors when I printf the whole tree.
The error occurs because you do free all data, but forget to indicate that your elements no longer contain valid data.
That is, after deleting, all elements' left and right members, and your own root itself still contain a value; they still contain the original values, but these no longer point to valid, allocated, memory.
The error does not directly occur within emptyTree because this works from the end nodes up to the top, and there is no reason to check "down". But as soon as you attempt to print root (and its descendants), you are accessing unallocated memory.
Insert
*root = NULL;
in your emptyTree function after
free(*root);
to fix it inside the emptyTree function, or set root to NULL after calling emptyTree.
Personally, I prefer the former, even though it's a minor overhead. That way, you only have a single function to delete a tree, instead of the recursive one plus a wrapper that also sets the root to NULL.
Related
I am working on a Graph problem, so my program has an initialization which sets all connection using an adjacencyList. Currently encountering a really weird bug and was wondering if anyone could give some insights as to what may be happening.
So I have a function that sets a connection
void setConnection(Graph g, int sVertex, int eVertex){
ListNode *newNode = (ListNode *) malloc(sizeof(ListNode*));
newNode->vertex = eVertex;
ListNode *temp = g.list[sVertex-1];
if (temp == NULL){ // Corresponding list is empty
newNode->next = NULL;
g.list[sVertex-1] = newNode;
}
else{ // Insert new node to the front
newNode->next = temp; // set newNode's next to current 'head'
g.list[sVertex-1] = newNode; // Replace head as newNode
}
//printf("Connection set from %d to %d\n", sVertex, g.list[sVertex-1]->vertex);
return;
}
After initialization, I usually attempt to print out the adjacencyList to check if the logic is correct. The function is as follow:
void printGraphList(Graph g){
int i;
ListNode* temp;
for(i=0;i<g.V;i++)
{
printf("|");
printf("%d:\t",i+1);
temp = g.list[i];
while(temp != NULL){
printf("%d -> ",temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
So here's the weird part, the code works fine most of the time, but occasionally crashes randomly when printing the adjancencyList. I debugged it down to
printf("%d -> ", temp->vertex);
For some reason, there are cases where the first node inserted does not have its ->next set to NULL properly. hence in the list traversal, it does not exit properly, and as such the temp->vertex is unobtainable, therefore causing the crash.
I have also debugged setConnection to ensure the links are properly set, like the actual pointer values themselves T.T
Below is an example of a working run, and a problem run. I printed an & before printing the vertex and and # after. As shown in the image, for vertex 7, it should be linked to only vertex 9 and 10, but in the problem run, it looks like the node for 9's next is not set to NULL properly, causing the program to crash in attempt to get node 9's->next->vertex as it does not exist...
As mentioned before, this happens once every 3 to 4 runs and i have no clue whats causing this inconsistency. Any help is appreciated! Thanks in advance.
Problem Example
Working Example
I am having some trouble with pointers in C. Basically, we are tasked with programming an N-ary tree (family tree). Any single node can have any number of children (0, 1, 2, ...). I am stuck at the part of adding a single parent and a single child.
Theoretically, the parent should be the root and the child should be the child of the root. My add_child method is as follows (so far):
Node* add_child(Node** root, char* parent, char* child) {
Node* new_node = malloc(sizeof(Node));
//check for correct memory allocation of new_node here
new_node->name = child;
new_node->children = NULL;
new_node->child_count = 0;
if (*root == NULL) {
Node* parent = malloc(sizeof(Node));
parent->name = parent;
parent->children = malloc(sizeof(NodeList*));
NodeList* list = malloc(sizeof(NodeList));
list->data = new_node;
list->next = NULL;
parent->children = &list;
parent->child_count = 1;
*root = parent;
return;
}
}
Here are the structs:
typedef struct FieldNode {
char* name;
NodeList** children;
size_t child_count;
} Node;
typedef struct FieldNode_L {
Node* data;
NodeList* next;
} NodeList;
Now that we have that out of the way, I'll move onto the print_tree function, we should print the tree breadth-first (level-by-level). I have written the algorithm for this already, but it gets stuck pushing the children of a node onto the queue. To do this:
NodeList* current = *listPtr;
while (current->data != NULL) {
Node* to_add = current->data;
// set up queuenode and push it to the queue
current = current->next;
}
So theoretically, it should run once, push to the queue, then set current to the next, which is null, go back to check the while-loop condition, and fail and continue through the rest of the print_tree method. But this doesn't happen.
After debugging with gdb for what seems like 5 hours, I can tell you this:
Before returning in add_child method, all of the memory locations are valid and point to the correct places. In gdb, with a breakpoint set, I can display all of the information through the root pointer (parent name, child count, and child name) by dereferencing.
In the print_tree method, all of the information retains from the root that was set in the add_child method EXCEPT the children.
The address that was set in the add_child method, and which I confirmed held the name I inputted had changed to a string filled with unicode characters ("\237\432\320....etc etc")
My algorithm correctly prints the parent name, but then fails when adding the children and goes into an infinite loop as described above in the last code block.
So all in all, I have no idea why the contents have changed. I suspect that I am assigning values/addresses wrong in add_child (because the information is retained within the add_child function, but is lost in the other method) but I am confused because the root is holding some information but not all of it across functions.
I am very new at C and still trying to learn all this pointer stuff, for example double pointers... Any help with this problem would be appreciated!
VALGRIND EDIT: As requested, here is the valgrind output of the program, although I don't see how it is helpful. My code runs into an infinite loop, so my program has no chance to clean up the mess. In the last code block, where I show where how/where it infinite-loops, I commented out code that allocated space for a QueueNode. After running forever, it racks up a bunch of allocates but only 2 frees. That's why the output says it has that many.
GCC EDIT: As requested, I ran gcc with the flags
-Wall -Wextra -pedantic
and received the following output:
10:26: warning: unused parameter 'argv' [-Wunused-parameter]
154:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
89:1: warning: control reaches end of non-void function [-Wreturn-type]
I fixed the last two (comparison between signed and unsigned and the control reaching the end of a non-void function). The unused parameter I need later on, so I can't change that yet. It shouldn't effect anything anyway.
After fixing those problems, nothing has changed - the same error still occurs.
Not sure what is going on with my code. Was implementing a simple binary search tree and got everything to work - had no problem inserting a bunch of elements. Then, while trying to add some file IO functionalities, all of the sudden my program was crashing. I thought perhaps I had messed something up with the file pointers and writing (though that doesn't really make sense either, since it leaves the rest of the code untouched), so I pulled up an archived version of the code, and BAM - crashing after 2 inputs even though it was fully working the last time I tried it!
Adding a bunch of debug print statements (sorry still need to learn to use the debugger), it seems the crash most often occurs at my malloc - but sometimes it randomly crashes at different points if I keep rerunning the program too.
I'm really confused by this. How is it that I was able to insert ~10 elements and now I somehow cant even insert 3? Task manager says I have ~4Gb of RAM free, and it's not like I'm doing some massive amount of inputs - this should cost memory absolutely nothing. Also how is it crashing in different places even though I'm running the exact same code?
I'd be very grateful for any insights. Running Windows 10, Codeblocks as the IDE. Code for the main and the function in question below. In most of my runs, the program crashes before the third insert reaches "Space Allocated", but sometimes it manages to insert it - and then the program crashes anyways, for no apparent reason.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node *BSTREE;
struct node
{
int data;
BSTREE left;
BSTREE right;
};
BSTREE insert(BSTREE root, int number);
BSTREE find(BSTREE root, int number);
void inOrderTraversal(BSTREE subtree);
int main(){
BSTREE root = NULL;
root = (insert(root, 2));
insert(root, 4);
insert(root, 1);
}
BSTREE insert(BSTREE root, int number)
{
printf("\n\nInside insert");
BSTREE temp = NULL;
if(!(root)){
printf("\nInside empty root");
temp = (BSTREE*)malloc(sizeof(BSTREE));
printf("\nSpace allocated");
temp->left = NULL;
temp->right = NULL;
printf("\nleft and right set to null");
temp->data = number;
printf("\n data set to number");
root = temp;
printf("\nroot is now temp; Before returning root");
printf("\n node data: %d %d %d", root->data, root->left, root->right);
return root;
}
if(number < root->data){
root->left = (insert(root->left, number));
}
else if(number > root->data){
root->right = (insert(root->right, number));
}
else if(number == root->data){
return root;
}
}
The line:
temp = (BSTREE*)malloc(sizeof(BSTREE));
is an excellent example of why Is it a good idea to typedef pointers? recommends 'No'.
You have two problems:
You're allocating a pointer to a pointer to a struct node to a pointer to a struct node — you don't need the * in the cast (and there are those who'd argue you don't need to cast the result of malloc()).
You're only allocating enough space for a pointer but you're using it as if it was big enough to hold a struct node; it isn't.
The basic fix is one of these lines:
temp = (BSTREE)malloc(sizeof(struct node));
temp = malloc(sizeof(*temp));
There isn't a way to use BSTREE in the first sizeof operator that I can think of. The second is actually a sound technique; it remains valid even if the type of temp changes. You can create various hybrids too.
I'd recommend using:
typedef struct BSTree BSTree;
struct BSTree
{
int data;
BSTree *left;
BSTree *right;
};
and then you'd write:
BSTree *temp;
temp = (BSTree *)malloc(sizeof(BSTree));
temp = malloc(sizeof(*temp));
You might note that the second alternative hasn't changed.
It seems as you are not returning the memory that you reserve with malloc. When using dynamic memory, it's important to release it again, otherwise you'll have a so called memory leak and the size will just increase until program crashes.
Function for releasing (freeing) memory is free();
A call should look something like free(temp);
I can not try it to make sure because I don't have your library used so I can't guarantee it works, but I hope it solves it.
I want to write a function which gets a pointer to a header of a linked list and deletes from the list every second member of it. The List is a linked elements of type element:
typedef struct element{
int num;
struct element* next;
}element;
I'm new to all these pointers arithmetic so I'm not sure I write it correctly:
void deletdscnds(element* head) {
element* curr;
head=head->next; //Skipping the dummy head//
while (head!=NULL) {
if (head->next==NULL)
return;
else {
curr=head;
head=head->next->next; //worst case I'll reach NULL and not a next of a null//
curr->next=head;
}
}
}
I kept changing it since I kept finding errors. Can you please point out any possible errors?
The algorithm is a lot simpler if you think of your linked list in terms of node pairs. Each iteration of your loop should process two nodes - head and head->next, and leave head equal to head->next->next upon exit. It is also important to not forget deleting the middle node, if you are cutting it out of the list, otherwise you are going to see memory leaks.
while (head && head->next) {
// Store a pointer to the item we're about to cut out
element *tmp = head->next;
// Skip the item we're cutting out
head->next = head->next->next;
// Prepare the head for the next iteration
head = head->next;
// Free the item that's no longer in the list
free(tmp);
}
It might be most straightforward to visualize this problem in recursive terms, like this:
// outside code calls this function; the other functions are considered private
void deletdscnds(element* head) {
delete_odd(head);
}
// for odd-numbered nodes; this won't delete the current node
void delete_odd(element* node) {
if (node == NULL)
return; // stop at the end of the list
// point this node to the node two after, if such a node exists
node->next = delete_even(node->next);
}
// for even-numbered nodes; this WILL delete the current node
void delete_even(element* node) {
if (node == NULL)
return NULL; // stop at the end of the list
// get the next node before you free the current one, so you avoid
// accessing memory that has already been freed
element* next = node->next;
// free the current node, that it's not needed anymore
free(node);
// repeat the process beginning with the next node
delete_odd(next);
// since the current node is now deleted, the previous node needs
// to know what the next node is so it can link up with it
return next;
}
For me, at least, this helps clarify what needs to be done at each step.
I wouldn't advise actually using this method because, in C, recursive algorithms may take up a lot of RAM and cause stack overflows with compilers that don't optimize them. Rather, dasblinkenlight's answer has the code that you should actually use.
I'm new to C so be patient with me if you see some really newbie error in my code!
As part of a homework, I need to create an ordered list in order to store some data. What I've done so far is to create the struct which will represent each node of the list (firstNode is a global variable that points to the first node of the list):
typedef struct Node {
struct Node *next;
int id;
int value;
}Node;
Node *firstNode = NULL;
After that I created a function that inserts a new node into the list by checking the values of the nodes. Nodes with smaller values should be before others. So what I did was this:
void addNewNode(int nodeId, int nodeValue) {
Node *newNode = (Node*) malloc(sizeof(Node));
Node *temp, *tempPrev;
newNode->id = nodeId;
newNode->value = nodeValue;
if(firstNode == NULL) {
newNode->next = firstNode;
firstNode = newNode;
}
temp = firstNode;
tempPrev = NULL;
while(temp->value < newNode->value) {
tempPrev = temp;
temp = temp->next;
}
if(tempPrev == NULL) {
newNode->next = firstNode;
firstNode = newNode;
}
else {
tempPrev->next = newNode;
newNode->next = temp;
}
}
The problem with the code above is that sometimes the program crashes, but I can't find the error!
Also, what I'm trying to do next is, if some nodes have the same value, then they are ordered according to their id (nodes with smaller IDs come first). How can I do this? I'm really confused!
The program crashes because in the while loop condition, you don't check whether the temp equals to NULL. In other words, if you try to insert a new node with a greater value than all the others already inside the list, temp reaches to the end of the list (so temp equals to NULL) and you try to get the value of that node! So a fix would be:
while(temp!=NULL && temp->value>newNode->value)
{
....
}
As for the id of the nodes, you could extend your while loop condition like this:
while(temp!=NULL && (temp->value<newNode->value || (temp->value==newNode->value && temp->id<newNode->id))
{
....
}
Also, the first if-statement, where you check whether firstNode is NULL, is not necessary in your case. If it's NULL, the program will not get into the while-loop and will go directly to the first if-statement after the while-loop.
By the way, nice code for a new programmer in C :-)
1.
if(firstNode == NULL) {
newNode->next = firstNode;
firstNode = newNode;
return; // done with inserting the first node...need not continue.
}
2.
// ensure temp is not null only then access its value.
while(temp && (temp->value < nodeId->value)) {
tempPrev = temp;
temp = temp->next;
}
for one thing, you have nodeID -> value in there. NodeID is an int, so this won't work.
As a method of debugging, I would create a simple test harness. In other words, a test program you write that runs through all the common scenarios you can think of (aka unit testing). Each unit test checks to ensure that it runs properly and generates the expected output. This way, you can be confident that if everything checks ok, you're good to go. If a unit test fails, you know exactly what's broken.
I would suggest constructing a couple of test cases that check your boundary conditions (e.g. add an element to an empty list; add an element that should end up at the front of an existing list; add an element that shold end up at the end of an existing list; add an element that should end up somewhere in the middle of an existing list). Make a "print" function that will print the elements in the list to the console for debug. That will at least help you narrow down what the context of your crash is. One possibility (I don't know how many adds you're doing) is that the program runs out of memory and malloc fails. You can check for that because I think malloc returns NULL if it fails to allocate the requisite memory.
Node *newNode = (Node*) malloc(sizeof(Node));
if(newNode == NULL)
{
printf("Out of Memory!");
return;
}