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.
Related
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;
}
My function insert is not working, after applying some sorting methods that I got at Google (http://teknosrc.com/linked-list-in-c-insertion-sort/).
Firstly, the structures that I'm going to use at it:
// This is the Node , where will be stored the item
struct no
{
Item * item;
struct no *prox;
};
typedef struct no No;
//This is the list, where will have the head node(No)
struct lista
{
char *nomeLista; //This is just a name of the list
No *cabeca; //This is the head node
int tamanho; //This is the amount of items inserted (forgot to implement this)
struct lista *prox; //This is the next list
};
typedef struct lista Lista;
//This is just the main list that will guard all the list of nodes in a linked way. No need to worry about this.
struct vetorListas
{
Lista *cabeca; //head list
int tamanho; //amount of lists
};
typedef struct vetorListas VetorListas;
//This is the item to be inserted
struct item
{
int id; //the ID used for the comparison of sort
char *nome; //just the name of it
};
typedef struct item Item;
In this function, nomeDaList is a string (char *) used to find the list by other function and i is the Item:
void *
insert(void * nomeDaLista, Item * i)
{
Lista * auxLista; //the list
auxLista = idl(nomeDaLista); //the function to get the list by it's name. It works, no worries.
//down here, is the sequence of codes translated to my program (got by the website I showed before)
No * temp = auxLista->cabeca;
No * prev = NULL;
No * ptr;
Item * itemTemp;
itemTemp = temp->item;
ptr = criaNo(i); //this function creates (makes the malloc and all) a node (No) and return the created node.
if(temp == NULL)
{
ptr->prox=NULL;
auxLista->cabeca = ptr;
return auxLista;
}
if(i->id < itemTemp->id)
{
ptr->prox = auxLista->cabeca;
auxLista->cabeca = ptr;
return auxLista;
} else
{
while(temp != NULL)
{
if(i->id > itemTemp->id)
{
prev = temp;
temp = temp->prox;
continue;
} else
{
prev->prox = ptr;
ptr->prox = temp;
return auxLista;
}
}
prev->prox = ptr;
}
}
Please help with this Segmentation fault (core dumped).
You have a check in this line
if(temp == NULL)
which should, and normally would, protect you against segfaults from accessing via NULL pointer.
However, a few lines before, you already dereference the unchecked temp, twice.
itemTemp = temp->item;
and
No * temp = auxLista->cabeca;
You should change the code to make sure that these lines only get executed, if tmp is non-NULL. E.g. split the variable definition and its initialisation and move the init after the check line.
You also receive a pointer from a function criaNo(i) and use it a few lines later, without checking it against NULL.
ptr->prox=NULL;
It is not clear, whether that is guaranteed to be non-NULL. You will have to "rubber-duck" that function, i.e. check in detail, whether it can return NULL.
Here is a nice decription of how to debug (mostly) without a debugger, also explaining "rubber-ducking".
https://ericlippert.com/2014/03/05/how-to-debug-small-programs/
For your problem of not knowing how to use a debugger:
How to debug using gdb?
For your problem of not using an IDE:
Find one, save pain.
My favorite search engine gives (for "free IDE c") my currently used free IDE as first match, the one I am thinking of switching to as third.
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.
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…
}
So I'm running into a bit of a wall here. I have a main.c program that plays around with linked lists, and at some points passes in a value of a node that's to be deleted from the list. The kicker was that it was supposed to do it using call by reference. I'm fairly certain (like...85%) that I've got all the things I need for the remove node function, but I'm probably just not implementing it right.
So this is the initializing function that all the others in my List.c file derive from:
// Call by reference
// This is a linked list without dummy head node!
void init(List *alist, int (*fComp)(void *, void *), void (*fPrint)(void *), void (*fFree)(void *))
{
if(alist != NULL)
{
alist->head = NULL;
alist->tail = NULL;
alist->size = 0;
alist->cmpData = fComp;
alist->printData = fPrint;
alist->freeData = fFree;
}
else
{
printf("Invalid NULL list pointer passed in!\n");
}
}
This is my removeNode function:
int removeNode(List *alist, void *obj){
Node *cur, *prev = alist->head, *start = (*alist).head;
void *temp = obj;
if(temp == cur) {
alist->head = cur->next;
free(cur);
return 1;
}
else if(obj != alist->head) {
for (cur = start->next; cur != NULL; cur = cur->next) {
if (alist->cmpData(cur->data, temp) == 0) {
prev->next = cur->next;
free(cur);
return 1;
} // end if
prev = cur;
} // end for
} // end else if
return 0;
} // end removeNode
"List *alist" and "void *obj" are the linked list elements and the element to be deleted, respectively that are passed in from main.c. The function is supposed to use cmpData (which needs to be passed two void pointers) from the init function to compare the current element being looked at with the element to be deleted then either return 1 if it does delete it or 0 if it doesn't.
Thank you in advanced for any and all help!
UPDATE So my code posting is now the one that I've got to work. It deletes the node as it is supposed to. HOWEVER, do I have enough free() in it? I have a memory leak checking program and it keeps telling me that I need two more free()'s in here, and it seems to specifically be the removeNode function since nowhere else in my program gets flagged.