I'm trying to implement ADT binary tree in C and I would like use API, which functions has form like foo(object, value). As far I wrote working tree for int value, but when I call BinTree_insert function I have to use operator"&" to get address of object. Is it possible to modify this function to omit & ?
typedef struct __bintree_node_t
{
int data;
struct __bintree_node_t* left;
struct __bintree_node_t* right;
}bintree_node_t;
static void __BinTree_insert(bintree_node_t** node, int value)
{
if(!(*node))
{
*node = __BinTree_newNode();
(*node)->data = value;
}
else if((*node)->data < value)
__BinTree_insert(&(*node)->left, value);
else if((*node)->data > value)
__BinTree_insert(&(*node)->right, value);
}
void BinTree_insert(bintree_node_t* node, int value)
{
//??????
}
int main(void)
{
bintree_node_t* root = 0;
BinTree_insert(root, 2); //sth like this
__BinTree_insert(&root, 1); //instead of this
}
You have the following options:
Instead of modifying the passed pointer to a pointer, you could return a new pointer instead. But that means using the returned value, which defeats the encapsulation a bit:
static void BinTree_insert(bintree_node_t* node, int value)
{
if (!node)
{
node = __BinTree_newNode();
node->data = value;
}
else if (node->data < value)
node->left = __BinTree_insert(node->left, value);
else if (node->data > value)
node->right = __BinTree_insert(node->right, value);
}
int main(void)
{
bintree_node_t* root = 0;
root = BinTree_insert(root, 2);
}
Or if you just want to change the initial call, you could maintain the pointer-to-pointer yourself:
int main(void)
{
bintree_node_t* root = 0;
bintree_node_t** rootPtr = 0;
__BinTree_insert(rootPtr, 2);
}
Or you could define a type which further encapsulates the pointer, but that adds quite a bit more code and memory allocation.
Not sure what the whole point is, though?
You've implemented your insert() function so that it modifies its first parameter. To do that, you have to pass the root by pointer; if you passed it by value (a bintree_node_t*), a change of the root inside BinTree_insert() would not be reflected outside the function (though changes to the root node would be).
For example, if the tree is empty (root equals NULL), your insertion function creates a new node, and has the root pointer point at that node; that can't be done if you want to keep the original root pointer, which would continue being NULL.
What you could do is have the insertion function return the new root. Then you could pass the old root as a bintree_node_t* (i.e. by value).
Related
So I have a piece of code, where I have to add a node to a BST. My struct is the following:
typedef struct _CC_TREE {
// Members
int Value;
struct _CC_TREE* LChild;
struct _CC_TREE* RChild;
} CC_TREE;
The insert function in the header file looks like this:
int TreeInsert(CC_TREE *Tree, int Value);
where I have to return the status of the insert.
I tried doing it with another function and add it to the Tree
CC_TREE* InsertNewNode(CC_TREE* Tree, int Value)
{
if (NULL == Tree)
{
Tree = (CC_TREE*)malloc(sizeof(CC_TREE));
Tree->LChild = NULL;
Tree->RChild = NULL;
Tree->Value = Value;
return Tree;
}
if (Value <= Tree->Value)
{
Tree->LChild = InsertNewNode(Tree->LChild, Value);
}
else if (Value >= Tree->Value)
{
Tree->RChild = InsertNewNode(Tree->RChild, Value);
}
return Tree;
}
int TreeInsert(CC_TREE *Tree, int Value)
{
CC_UNREFERENCED_PARAMETER(Tree);
CC_UNREFERENCED_PARAMETER(Value);
Tree = InsertNewNode(Tree, Value);
return 0;
}
I try and construct the tree in my main function:
int retVal = -1;
CC_TREE* usedTree = NULL;
retVal = TreeCreate(&usedTree);
if (0 != retVal)
{
printf("TreeCreate failed!\n");
goto cleanup;
}
retVal = TreeInsert(usedTree, 20);
if (0 != retVal)
{
printf("TreeInsert failed!\n");
}
but for some reason the usedTree remains null. I know that I should use CC_TREE** Tree in the insert function, but I am not allowed to.
The insert function in the header file looks like this:
int TreeInsert(CC_TREE *Tree, int Value);
If you cannot change the function signature or (ew!) use a global variable to return the root pointer to the caller, then your best alternative is probably to use a dummy tree root. That would look something like this:
int TreeInsert(CC_TREE *Tree, int Value) {
// Tree points to a dummy root node containing no data.
// Tree->LChild is the actual root pointer
CC_TREE *root = Tree->LChild;
int status = 0;
// ... perform insertion, possibly resulting in a different value for the
// root pointer ...
Tree->LChild = root;
return status;
}
That assumes that the first argument to TreeInsert() is always a valid pointer to a CC_TREE. If you do this, then all other tree functions should work analogously.
You would use that from main() like so:
int retVal;
CC_TREE dummy_tree_root = { 0 };
retVal = TreeInsert(&dummy_tree_root, 42);
Note that this approach in effect uses a double pointer via an indirect route (no pun intended). A CC_TREE * is not itself a double pointer, but there are still two levels of indirection between that pointer and either the left or the right child of the node to which it points.
Note also that a cleaner way of doing this would involve providing a wrapper structure representing the overall tree instead of using a bare tree node or tree node pointer for the purpose. The data structures would be something like this:
struct node {
int value;
struct node *left;
struct node *right;
};
struct tree {
struct node *root;
// optionally other data, such as size, height, etc.
};
I am trying to write a code to transverse a tree data structure using inorder transversal and store all the nodes onto an array.
I came up with this code below but it doesn't work, as the index of any previous recursion has already been passed on in the function.
int *inorderTransversal(AVLTreeNode *node, AVLTreeNode *array[], int index)
{
if (node == NULL)
return index;
inorderTransversal(node->left, array, index);
nodesArray[index] = node;
index++;
inorderTransversal(node->right, array, index);
return index;
}
I know I could possibly declare a static 'index' value inside the function, and it might work? But the downside is it makes 'index' stays in the memory for the entire duration of the program e.g.
void *inorderTransversal(AVLTreeNode *node, AVLTreeNode *array[])
{
static int index = 0;
if (node == NULL)
return;
inorderTransversal(node->left, array);
nodesArray[index] = node;
index++;
inorderTransversal(node->right, array);
return;
}
Or I could declare the index outside the function prior? e.g.
AVLTreeNode *array[tree->size];
int index = 0;
void *inorderTransversal(AVLTreeNode *node) {
if (node == null)
return;
inorderTransversal(node->left);
array[index] = node;
index++;
inorderTransversal(node->right);
}
Could someone help me to amend the code to include the 'index' increments inside the function without using static? Much appreciated!
Your first attempt was close. You want to pass in index as an int *. Then you can dereference it and update it.
void inorderTransversal(AVLTreeNode *node, AVLTreeNode *array[], int *index)
{
if (node == NULL)
return;
inorderTransversal(node->left, treeSize, index);
nodesArray[*index] = node;
(*index)++;
inorderTransversal(node->right, treeSize, index);
}
When you call this function, you pass the address of an int which has been initialized to 0. When the recursion ends it will hold the number of elements in the list.
I have this C function which is supposed to find an element in the linked list which has a specific "pos" value, delete it, and return the deleted value to the calling function. It does delete the item, but the change isn't saved in the calling function, the list just doesn't get updated with the new changes.
My list is structured like this:
struct list{
int value;
int pos;
struct list * next_ptr;
};
And my C function is this:
bool findDeleteElement(struct list **ptr, int position, int *value){
struct list** temp = ptr;
if(*ptr!=NULL){
while((*ptr)->pos!=position) ptr=&(*ptr)->next_ptr; //Gets to desired node
temp=ptr;
value=&(*ptr)->value; //saves the value
temp=&(*temp)->next_ptr; //Goes to next node
ptr=temp; //Makes ptr point to next node
return 1;
}
else return 0;
}
I just can't see what I'm missing.
I'm a beginner so I probably made a simple mistake.
Change to:
*value = (*ptr)->value; //saves the value
You only set value, the local copy of your external variable's address. This does not change your external variable in the calling function.
Some question:
What happens when position has the wrong value, such that no node is found?
What's the purpose of temp = ptr;, because temp is overwritten by temp = &(*temp)->next_ptr; without having been used.
Disclaimer: I've not further checked this function.
I kindly advise you to take on other code formatting rules that add more air and make things more readable. Here's an example:
bool findDeleteElement(struct list **ptr, int position, int *value)
{
struct list** temp = ptr;
if (*ptr != NULL)
{
// Gets to desired node
while((*ptr)->pos != position)
{
ptr = &(*ptr)->next_ptr;
}
temp = ptr;
*value = (*ptr)->value; // Saves the value
temp = &(*temp)->next_ptr; // Goes to next node
ptr = temp; // Makes ptr point to next node
return 1;
}
else
{
return 0;
}
}
You are confused about pointers and dereferencing and what & and * actually do. This is a normal state of affairs for a beginner.
To start with, ptr and value when used without * preceding them are function arguments and like automatic (local) variables they disappear when the function scope exits. So this statement:
value=&(*ptr)->value;
Merely changes the value of value i.e. what it points to and has no visible effect to the caller. What you need to change is the thing that value points to. i.e. the statement should look like this:
*value = (*ptr)->value;
The difference is that instead of setting value to the address of (*ptr)->value it sets what valuepoints to to (*ptr)->value.
You have a similar problem with ptr. But your problems are more subtle there because you are also trying to use it as a loop variable. It's better to separate the two uses. I'd write the function something like this:
bool findDeleteElement(struct list **head, int position, int *value)
{
struct list* temp = *head;
struct list* prev = NULL;
while(temp != NULL && temp->pos != position)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL) // position not found
{
return false;
}
else
{
*value = temp->value;
// Now need to delete the node.
if (prev != NULL)
{
// If prev has been set, we are not at the head
prev->next = temp->next; // Unlink the node from the list
}
else // We found the node at the head of the list
{
*head = temp->next;
}
free(temp); // Assumes the node was malloced.
return true;
}
}
The above is not tested or even compiled. I leave that as an exercise for you.
int delete(struct llist **pp, int pos, int *result)
{
struct llist *tmp;
while ( (tmp = *pp)) {
if (tmp->pos != pos) { pp = &tmp->next; continue; }
*result = val;
*pp = tmp->next;
free(tmp);
return 1;
}
return 0;
}
I'm having a problem with changing the address of a pointer in a struct.
The funcion receives a service type (a pointer to a struct) and an ID. The service contains a linked list of type apartments (pointer to an apartment struct), and I want to find the apartment with the given ID and remove it from the list. The problem is- when I go back to the original function, service->listedApartment still points the same way as before..
ApartmentServiceResult serviceDeleteById(ApartmentService service, int id) {
Node previous = NULL;
Node after = NULL;
Node current = service->listedApartments;
while (current != NULL) {
after = current->next;
if (current->id == id) {
apartmentDestroy(current->apartment); //deletes the apartment
free(current);
if (previous == NULL) {
service->listedApartments = after;
} else {
previous->next = after;
service->listedApartments=previous;
}
return APARTMENT_SERVICE_SUCCESS;
}
previous = current;
current = current->next;
}
return APARTMENT_SERVICE_NO_FIT;
}
Are you sure that you're passing a reference?
With this line you're passing your struct by value, that means the function will make a copy of the passed paramether and modify it, without changing the value outside.
ApartmentServiceResult serviceDeleteById(ApartmentService service, int id) {
To pass by reference you have to explicitly put the * and treat the reference accordingly:
ApartmentServiceResult serviceDeleteById(ApartmentService * service, int id) {
Unless you did some magic with the typedef, I guess it might have been the issue.
Removing the (not shown in the OQ) typedefs, and using just struct xx* and struct yy*, the fragment can be reduced to:
ApartmentServiceResult serviceDeleteById(struct xx *service, int id) {
struct yy **pp, *p;
for (pp= &service->listedApartments; (p = *pp); pp = &p->next) {
if (p->id != id) continue;
apartmentDestroy(p->apartment);
*pp = p->next; /* steal the pointer */
free(p);
return APARTMENT_SERVICE_SUCCESS;
}
return APARTMENT_SERVICE_NO_FIT;
}
In link list the very first thing to remember is that each time you call a function must be call by ref because you want that manipulation in your link list and your function serviceDeleteById is receiving its arguments by value. So modify it and try to run the code.
void del(int d)
{
struct node *temp,*ptr;
temp=start;
while(temp!=NULL)
{
if(temp->link->info==d)
{
ptr=temp->link;
temp->link=ptr->link;
free(ptr);
}
temp=temp->link;
}
}
This code sample will help you with code. You can check more here.
I created two struct
typedef struct node
{
struct node* left;
struct node* right;
int data;
} node;
typedef struct head
{
int count;
struct node* root;
} head;
and here's the function that i'm trying to use to insert data into a tree.
int insert(struct node* root, int value)
{
node* newnode =(node*)malloc(sizeof(node));
newnode->data=value;
newnode->left=NULL;
newnode->right=NULL;
if(root==NULL)
{
root=newnode;
return 1;
}
if(value<root->data)
{
if(root->left==NULL)
{
root->left=newnode;
return 1;
}
else
{
return insert(root->left,value);
}
}
else if(value==root->data)
{
printf("data already exist\n");
free(newnode);
return 0;
}
else
{
if(root->right==NULL)
{
root->right=newnode;
return 1;
}
else
{
return insert(root->right,value);
}
}
}
and when i operate
head* BSThead=(head*)malloc(sizeof(head));
insert(BSThead->root,10);
i can see that insert function successfully enters the first if and operate the line root=newnode;, and i can see the address that it had given.
but when this function ends and i go back to the main function to access it through
printf("%d",BSThead->root);
this line just prints 0, which I think means BST->root is currently null.
By what I have learned, the data created by malloc function has the scope over it's function unlike normal value. So I thought although newnode was created in the insert function, doesn't get destroyed like normal variables when the insert function ends and thus i can use it all the time while program runs.
These lines:
if(root==NULL)
{
root=newnode;
return 1;
}
modify root in the function but don't change the value of the same variable in the calling function.
The value of root in the calling function continues to be NULL and you leak every node allocated by the call to malloc.
One way to fix this is to pass a pointer to root.
int insert(struct node** root, int value)
{
...
if(*root==NULL)
{
*root=newnode;
return 1;
}
...
}
and call the function using:
insert(&(BSThead->root),10);
One problem is that you are using:
head* BSThead = (head*)malloc(sizeof(head));
insert(BSThead->root, 10);
This passes an unchecked pointer to uninitialized data to the function. Only if you're unlucky will that be a null pointer that you're passing. The function cannot modify the value in BSThead->root because you are passing its value, not a pointer to it. You also aren't passing the whole of the head structure, so the insert() code cannot update the count.
You need to initialize your head structure before using it. When you do use it, you need to pass either a pointer to the head structure into the function, or you need to pass the address of the root member to the function so that the function can update it:
head* BSThead = (head*)malloc(sizeof(head));
if (BSThead != 0)
{
BSThead->count = 0;
BSThead->root = 0;
/* Either */
insert(BSThead, 10); // And insert can update the count
/* Or */
insert(&BSThead->root, 10); // But insert can't update the count!
…use the list…
…free the list…
}