pointed data in function with malloc keeps disappearing outside of it - c

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…
}

Related

Omitting ampersand in function call

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).

Deleting a linked list node in a C function doesn't transfer to the calling function

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;
}

why is **head is used here instead of *head?

I know how pointers works.
I done similar problem with this way
deleteNode(struct node *head_ref, int key);
which is working and # here http://quiz.geeksforgeeks.org/linked-list-set-3-deleting-node/ they have used
deleteNode(struct node **head_ref, int key);
which also correct but is there reason to do so , will 1st one fails in any condition or is it bad way etc.
struct linked_list *deleteNode(struct linked_list *head, int key )
{
struct linked_list *prevNode,*current,*temp;
if( head==NULL)
return head;
if(head->data==key)
{
if(head->next==NULL)
{ free(head);
return NULL;
}
else
temp=head->next;
free(head);
return temp;
}
prevNode= head;
current=head->next;
printf("\n %d\n",(current->data));
while((current!=NULL) && (current->data!=key))
{ printf("\n here");
prevNode= current;
current=current->next;
}
if(current==NULL){
printf("\n element not present in list !\n");
return head;
}
if(current->next==NULL)
prevNode->next=NULL;
else
prevNode->next=current->next;
free(current);
return head;
}
head=deleteNode(head,key);
If you need to delete the head node, the first function won't work because you can't change the head node. The second function takes the address of the head node so it can be changed if need be.
The deleteNode function in the link contains the following:
struct node* temp = *head_ref, *prev;
// If head node itself holds the key to be deleted
if (temp != NULL && temp->data == key)
{
*head_ref = temp->next; // Changed head
free(temp); // free old head
return;
}
You can see here that it dereferences head_ref to change what it points to.
Let's forget the linked list and just think of updating a variable. There are two, equally valid ways to do it:
// 1. pass back
int update_int1(int val) {
return val + 1;
}
void caller1() {
int var = 1;
var = update_int1(var);
}
// 2. write back
void update_int2(int *val) {
*val += 1;
}
void caller2() {
int var = 1;
update_int2(&var);
}
This is easy to understand, so let's do the same thing with a pointer:
// 1. pass back
char *update_ptr1(char *ptr) {
return ptr + 1;
}
void caller1() {
char *ptr = malloc(10);
ptr = update_ptr1(ptr);
}
// 2. write back
void update_ptr2(char **ptr) {
*ptr += 1;
}
void caller2() {
char *ptr = malloc(10);
update_ptr2(&ptr);
}
It works exactly the same as for int! The key is there's always one more star if you want to write back, not pass back.
Which pattern you choose is up to you. The write-back approach is popular for linked lists.
When you write *b==>access contents of address contained in b.
When you write **c==>Access contents of contents of address contained in c.

linked List in a struct

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.

Global linked list pointing to NULL when passed through a function

I am facing this issue, in which if I am passing a linked list (which I defined as global) through a function (to insert a node), I am always getting a NULL value once the pointer returned to main function.
However, if I am adding the node to the global defined, it is working fine which is expected too. Can someone please help me why this piece of code didn't work and *list always points to NULL
struct node{
int val;
struct node *next;
};
typedef struct node node;
static node *list=NULL;
boolean add_node(node *list, int n, int val)
{
node *temp=NULL;
temp = (node *)malloc(sizeof(node));
temp->val = val;
temp->next = NULL;
if((list==NULL) && (n!=0))
{
printf("link list is NULL and addition at non zero index !");
return (FALSE);
}
if(list==NULL)
{
printf("list is NULL ");
list= temp;
}
else if(n==0)
{
temp-> next = list;
list=temp;
}
else
{
node *temp2;
temp2 = list;
int count =0;
while(count++ != (n-1))
{
temp2 = temp2->next;
if(temp2==NULL)
{
printf("nth index %d is more then the length of link list %d ",n,count);
return (FALSE);
}
}
node *temp3;
temp3 = temp2->next;
temp2-> next = temp;
temp->next = temp3;
}
printf("List after node insertion \n");
print_link_list(list);
return (TRUE);
}
main()
{
c= getchar();
switch(c)
{
case 'I':
{
printf("Insert a index and value \n");
int index,value;
scanf_s("%d",&index);
scanf_s("%d",&value);
if(add_node(list,index,value)==FALSE)
{
printf("Couldn't add the node \n");
}
if(list==NULL)
{
printf("\n After Insert op.,list is NULL, add %x",list);
}
else
{
printf("After Inset op., list is not Null, add %x",list);
}
}
break;
case 'D':
....
}
The global variable list is never modified, only the parameter list.
You probably want that parameter to be a pointer to a pointer, and assign through, instead of to, the parameter.
Try changing the function definition to use a pointer to a pointer:
boolean add_node(node **list, int n, int val)
You need to do this because your global variable list needs to be updated. The global is a pointer: an address. In your add_node function when you say list = temp you are only modifying the local pointer (also named list). When you leave the function the global list remains unchanged. However, if you pass a pointer to that global pointer (the pointer to a pointer) you are then able to modify the address stored in the original pointer.
An example:
int *pGlobal = NULL;
void someThing(int *pInt)
{
int LocalInt = 3;
pInt = &LocalInt; // I can change where this pointer is pointing - it's just a copy
// pGlobal remains unchanged
}
void someThingElse(int **ppInt)
{
// I am now modifying the ADDRESS of a pointer that we have the address of
*ppInt = malloc(sizeof(int));
// pGlobal has been changed to point at my allocated memory
}
void main()
{
// This passes a COPY of the address held in pGlobal
someThing(pGlobal);
// Here we are now passing a pointer (address) TO another pointer.
// The pointer pGlobal does occupy some real space in memory. We are passing a
// COPY of the value of its location so we can modify it.
someThingElse(&pGlobal);
}
Also, for good practice, don't name a global the same as a local variable (list) or parameter - it'll compile but can easily cause problems/confusion/bugs!

Resources