How to free a tree struct using double pointer? - c

I have to free a tree and set his root to NULL using a particular function. I tried to use a recoursive method. But if I compile i get some warnings about "incompatible pointer type" and I'm not able to resolve it. This is the struct:
typedef struct node {
int key;
struct node *left, *mid, *right;
} node_t;
And here the function. The first line cannot be changed:
void free_tree (node_t ** root){
if(root != NULL){
free_tree((*root)->left);
free_tree((*root)->mid);
free_tree((*root)->right);
free(*root);
}
return;
}
Any help would be appreciated

Your function expected a pointer to a pointer-to-node. You're giving it a pointer-to-node three times in your recursive calls. Further, you're not validating that the pointer-to-pointer, and the pointer it points to, are non-null; you're only validating the former.
In short, your function should look like this:
void free_tree (node_t ** root)
{
if(root && *root)
{
free_tree(&(*root)->left);
free_tree(&(*root)->mid);
free_tree(&(*root)->right);
free(*root);
*root = NULL;
}
}
The last functional line is optional, but frankly it's pointless to do this with pointers-to-pointers unless you're going to do that anyway, as it sets the caller's pointer to NULL after obliterating the tree. Given a properly built tree, your caller should deliver the address of the tree root when destroying the entire tree, as:
node_t *root = NULL;
// ... build tree ...
free_tree(&root);
// root is now NULL; tree is destroyed

Your question cannot be answered very clearly but at least I can tell you why you have this warning about incompatible pointer type :
Your function prototype is
void free_tree (node_t ** root);
It's argument is a node_t **.
Your struct is
typedef struct node {
int key;
struct node *left, *mid, *right;
} node_t;
So in your function :
void free_tree (node_t ** root)
{
if(root != NULL)
{
free_tree((*root)->left); <<< '(*root)->left' is of type 'node_t *'
free_tree((*root)->mid); <<< '(*root)->mid' is of type 'node_t *'
free_tree((*root)->right); <<< '(*root)->right' is of type 'node_t *'
free(*root);
}
return;
}
You call you function giving a node_t * as argument whereas your function expects a node_t **

Related

Why I need to add '&' when calling the function

typedef struct sTree {
int key;
struct sTree* p;
struct sTree* left;
struct sTree* right;
} sTree;
typedef sTree* tree;
void treeInsert(tree* root);
int main(){
srand((unsigned)time(NULL));
tree *root = NULL;
treeInsert(&root);
return 0;
}
void treeInsert(tree* root){
......
}
I don't understand why I have to pass '&' when calling tree insert (&root instead of root).
I've created a struct representing a node of binary tree and I declared a pointer to the root of the tree as 'tree*'.
So 'root' is double pointer. The function 'treeInsert' expects a double pointer. If I pass simply 'root' it takes the value (NULL) else with the operator '&' it points correctly to the root. The problem is:
passing '&root' I'm not passing a triple pointer? Can someone explain why?
regarding:
treeInsert(&root);
the need for the & is because the function: treeInsert() will need to modify the contents of the pointer. Without the & any assignment to that passed parameter will only change the parameter on the call stack and not the the contents of the parameter in main()
regarding:
tree *root = NULL;
Since tree is already a pointer, this results in (effectively)
tree ** root = NULL;
which will not accomplish what is needed.
A prime example of why a pointer should NOT be hidden in a typedef statement
the following proposed code is clear about what is wanted:
struct sTree
{
int key;
struct sTree* p;
struct sTree* left;
struct sTree* right;
};
typedef struct sTree tree;
void treeInsert(tree** root);
int main( void )
{
srand((unsigned)time(NULL));
tree *root = NULL;
treeInsert(&root);
return 0;
}
void treeInsert(tree** root)
{
tree *localroot = *root; // now 'localroot' is a pointer to the variable `root` in function: `main()`
......
}

Typedef struct cannot be cast to pointer

I've seen this question in multiple posts but I have yet to find one that has a good explanation for me. Im trying to create a linked list but the struct nor the functions cant be called without getting the error cannot cast to a pointer. Its really bugging me. Any help would be appreciated on how to get this working right. Heres some of the code below thats the issue.
typedef struct node
{
void *data;
struct node *next;
} node;
node *head = NULL;
node* create(void *data, node *next)
{
node *new_node = (node*)malloc(sizeof(node));
if(new_node == NULL)
{
exit(0);
}else{
new_node->data = data;
new_node->next = next;
return new_node;
}
}
node* prepend(node *head, void *data)
{
node *new_node = create(data,head);
head = new_node;
return head;
}
void preload_adz(int adz_fd)
{
struct adz adz_info;
char adz_data[40];
char adz_text[38];
int adz_delay;
char adz_delayS[2];
read(adz_fd,adz_data,40);
strncpy(adz_text,adz_data + 2,40-2);
sprintf(adz_delayS, "%c%c",adz_data[0],adz_data[1]);
adz_delay = atoi(adz_delayS);
adz_info.delay = adz_delay;
strncpy(adz_info.text,adz_text,38);
head = prepend(head, (void*)adz_info); //<---This line throws the error
while(read(adz_fd,adz_data,40) > 0)
{
}
}
struct adz adz_info;
...
head = prepend(head, (void*)adz_info); //<---This line throws the error
The problem here is adz_info is not a pointer, it's the actual struct on the stack. Passing adz_info into a function will copy the struct.
You need a pointer to that struct. Use & to get its address. Once you have the pointer, you don't need to cast it to void pointer, that cast is automatic.
head = prepend(head, &adz_info);
Note that casting is a bookkeeping thing. Casting to void * doesn't turn a struct into a pointer, it says "compiler, ignore the declared type of this variable and just trust me that this is a void pointer".

Array of Structurer in C

I was just brushing my pointer concepts and it seems its really messed up over time.
I was trying to implement BFS in binary tree.
Pseudo Code :
1) tempNode = root node
2) while tempNode is not null
print data at tempNode
enqueue left and right child
tempNode = dequeue
Here's my code :
#include <stdio.h>
#include <stdlib.h>
#define MAX_Q_SIZE 100
/**
* Using Queue to keep track of next nodes to be visited
*/
struct node
{
int data;
struct node *left;
struct node *right;
};
struct node *createQueue(int *front, int *rear)
{
struct node *queue = (struct node*)malloc(sizeof(struct node) * MAX_Q_SIZE);
*front = *rear = 0;
return queue;
}
void enQueue(struct node *queue, int *rear, struct node *newNode)
{
queue[*rear].data = newNode->data;
queue[*rear].left = newNode->left;
queue[*rear].right = newNode->right;
(*rear)++;
}
struct node *deQueue(struct node *queue, int *front)
{
(*front)++;
return &queue[*front - 1];
}
struct node *newNode(int data)
{
struct node *node = (struct node*)malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
void printBFS(struct node *root)
{
int front,rear;
struct node *queue = createQueue(&front, &rear);
struct node *tempNode = root;
while(tempNode != NULL)
{
printf("%d ",tempNode->data);
if(tempNode->left != NULL)
enQueue(queue,rear,tempNode->left);
if(tempNode->right != NULL)
enQueue(queue,rear,tempNode->right);
tempNode = deQueue(queue,front);
}
}
int main()
{
struct node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
printBFS(root);
return 0;
}
I am getting following 4 types of warnings :
BFS2.c: In function ‘printBFS’:
BFS2.c:60:13: warning: passing argument 2 of ‘enQueue’ makes pointer from integer without a cast [enabled by default]
enQueue(queue,rear,tempNode->left);
^
BFS2.c:23:6: note: expected ‘int *’ but argument is of type ‘int’
void enQueue(struct node *queue, int *rear, struct node *newNode)
^
BFS2.c:63:9: warning: passing argument 2 of ‘deQueue’ makes pointer from integer without a cast [enabled by default]
tempNode = deQueue(queue,front);
^
BFS2.c:34:14: note: expected ‘int *’ but argument is of type ‘int’
struct node *deQueue(struct node *queue, int *front)
Can anyone please help me to clarify the doubts as to why I am getting the warnings. I am unable to figure out the problems here. :(
You are passing int variables where int* (pointer to int) is expected. Pass the address of an int variable with & the address of operator. Multiple examples :
enQueue(queue, &rear, tempNode->left);
enQueue(queue, &rear, tempNode->right);
tempNode = deQueue(queue, &front);
As David has pointed out, the program will crash (segmentation fault). You may want to rethink the design of deQueue and/or what should happen if both tempNode->left and tempNode->right are NULL.
Instead of passing front and rear to enQueue() and deQueue(), pass &front and &rear. The & (address-of operator) takes the address of the variable. Since both front and rear are ints, this operator will create the correct result, an int *.
As an aside: don't cast the return value of malloc().
Your immediate pointer problems come from attempting to pass an int as a pointer:
int front,rear;
...
enQueue(queue,&rear,tempNode->left);
// enQueue(queue,rear,tempNode->left);
You have the same issue with deQueue immediately following. However, you have larger issues to deal with. Once you fix the pointer issues you will be faced with a Segmentation fault..
And to not leave you hanging, you simply need to go back and rework your queue implementation, it is a wreck. You will generate a Segmentation fault because your value for front in deQueue grows unchecked until i reaches a value of 100 and you attempt to write beyond the end of your MAX_Q_SIZE block of memory.
If you are brushing up on pointers, then don't torture pointers to try and shoehorn them into array syntax. There is no need for passing struct node *queue and then attempting to find array index syntax that will work:
queue[*rear].right = newNode->right;
when a simple pointer expression will do:
(queue + *rear)->right = newNode->right;
The same applies to:
return (queue + *front - 1); // syntax only your queue logic need fixing
This will make your code much more readable and reduce the chance for error when you pass pointers but then try and make the pointer work with something like:
return &queue[*front - 1];

Trouble with signature of function to add node to end of linked list

In a program I'm writing I need a linked list, so it's a pretty specific implementation. It needs:
the ability to add a node to the end
the ability to remove a node whose data matches a specified value
The data is a cstring, no more than 20 characters in length. I'm not very experienced with C and am getting errors with the following signature void addToEnd(llist root, char entery[51]). I tried replacing llist with node but then the error is "unknown type name node". How can I get rid of this?
Here's the code
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct node
{
char entery[51];
struct node* next;
} llist;
/*may be losing root address permanently*/
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
node last = malloc(sizeof(struct node));
root->next = last;
strcpy(last, entery);
}
int main()
{
struct node *root = malloc(sizeof(struct node));
root->next = NULL;
strcpy(root->entery, "Hello");
struct node *conductor = root;//points to a node while traversing the list
if(conductor != 0)
while(conductor->next != 0)
conductor = conductor->next;
/* Creates a node at the end of the list */
conductor->next = malloc(sizeof(struct node));
conductor = conductor->next;
if (conductor == NULL)
{
printf( "Out of memory" );
return EXIT_SUCCESS;
}
/* initialize the new memory */
conductor->next = NULL;
strcpy(conductor->entery, " world\n");
addToEnd(root, " at the");
addToEnd(root, " end");
/*print everything in list*/
conductor = root;
if(conductor != NULL)
{
while(conductor->next != NULL)
{
printf("%s", conductor->entery);
conductor = conductor->next;
}
printf("%s", conductor->entery);
}
return EXIT_SUCCESS;
}
One thing I'm unclear about, is in all the examples I've seen is they typedef the struct. Why? Let me elaborate: how do you know if you want to be passing just node or struct node. Also I don't really see the point, struct node isn't that much longer than a single typedef'd name.
Problems:
line 12: void addToEnd(llist root, char entery[51]) shall be void addToEnd(llist *root, char entery[51]). Here root must be a pointer type or you actually can not modify its value inside the function and make it visible outside the function.
line 16: node last = malloc(sizeof(struct node)); shall be struct node *last = malloc(sizeof(struct node));. Since in C you must reference a type name with the keyword struct, and also it shall be a pointer or it cannot be initialized with malloc.
As for your typedef question, I believe it is optional and people use it only for convenience. Personally I don't use typedef on a struct very often.
EDITED:
Also your code comes with bugs. Sorry I was only focusing on the syntax before.
Please notice that malloc in C don't assure you that the allocated memory is zeored, it's actually could be anything inside. So you need to fill it manually: to add a line last->next = NULL; at the end of addToEnd.
To refer to your struct of the linked list, use struct node, after the typedef, you can also use llist. You can also ues, as the linked question uses.
typedef struct node
{
char entery[51];
struct node* next;
} node;
In this style, you can use node the same as struct node.
The syntax error you are facing is, you misused the arrow operator ->, it's used with pointers of struct. For struct, use the dot operator .
So for the function
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
You should pass in a pointer:
void addToEnd(llist* root, char entery[51])

C struct and malloc problem (C)

It's amazing how even the littlest program can cause so much trouble in C.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *leftChild;
struct node *rightChild;
} node;
typedef struct tree {
int numNodes;
struct node** nodes;
} tree;
tree *initTree() {
tree* tree = (tree*) malloc(sizeof(tree));
node *node = (node*) malloc(sizeof(node));
tree->nodes[0] = node;
return tree;
}
int main() {
return 0;
}
The compiler says:
main.c: In function 'initTree':
main.c:17: error: expected expression before ')' token
main.c:18: error: expected expression before ')' token
Can you please help?
You're using two variables named tree and node, but you also have structs typedefed as tree and node.
Change your variable names:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *leftChild;
struct node *rightChild;
} node;
typedef struct tree {
int numNodes;
struct node** nodes;
} tree;
tree *initTree() {
/* in C code (not C++), don't have to cast malloc's return pointer, it's implicitly converted from void* */
tree* atree = malloc(sizeof(tree)); /* different names for variables */
node* anode = malloc(sizeof(node));
atree->nodes[0] = anode;
return atree;
}
int main() {
return 0;
}
tree and node is your case are type names and should not be used as variable names later on.
tree *initTree() {
tree *myTree = (tree*) malloc(sizeof(tree));
node *myNode = (node*) malloc(sizeof(node));
myTree->nodes[0] = myNode;
return myTree;
}
Change (tree*) and (node*) to (struct tree*) and (struct node*). You can't just say tree because that's also a variable.
Change the body of initTree as follows:
tree* myTree = (tree *)malloc(sizeof(tree));
node *myNode = (node *)malloc(sizeof(node));
myTree->nodes[0] = myNode;
return myTree;
Don't use typedef'ed names as variable names, and there is not need to cast malloc(); in C.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *leftChild;
struct node *rightChild;
} node;
typedef struct tree {
int numNodes;
struct node** nodes;
} tree;
tree *initTree() {
tree->nodes[0] = malloc(sizeof(node));
return malloc(sizeof(tree));
}
int main() {
return 0;
}
I second that Mehrdad's explanation is to the point.
It's not uncommon that in C code you define a variable with the same name as the struct name for instance "node node;". Maybe it is not a good style; it is common in, e.g. linux kernel, code.
The real problem in the original code is that the compiler doesn't know how to interpret "tree" in "(tree*) malloc". According to the compiling error, it is obviously interpreted as a variable.
Apart from the original question, this code, even in it's correct forms will not work, simply due to the fact that tree::nodes (sorry for the C++ notation) as a pointer to a pointer will not point to anything usefull right after a tree as been malloced. So tree->nodes[0] which in the case of ordinary pointers is essentially the same like *(tree->nodes), can't be dereferenced. This is a very strange head for a tree anyway, but you should at least allocate a single node* to initialize that pointer to pointer:
tree *initTree() {
/* in C code (not C++), don't have to cast malloc's return pointer, it's implicitly converted from void* */
tree* atree = malloc(sizeof(struct tree)); /* different names for variables */
/* ... */
/* allocate space for numNodes node*, yet numNodes needs to be set to something beforehand */
atree->nodes = malloc(sizeof(struct node*) * atree->numNodes);
node* anode = malloc(sizeof(struct node));
atree->nodes[0] = anode;
return atree;
}
Interestingly, it does compile cleanly if you simply write the allocations as:
tree *tree = malloc( sizeof *tree );
It is often considered better style to use "sizeof variable"
rather than "sizeof( type )", and in this case the stylistic
convention resolves the syntax error. Personally, I think
this example is a good case demonstrating why typecasts are
generally a bad idea, as the code is much less obfuscated if
written:
struct tree *tree = malloc( sizeof *tree );

Resources