I am trying to learn C, and as many people, I have been a little stuck with pointers. Anyways, I made a recursive function that destroys my linked list, but as I have debugged, when I am back from the function the head of the list is not null as it should be, so I'm guessing it's some basic misunderstanding with pointers. Here's the function:
void destroy(struct node *n) {
if (!n) return;
destroy(n->next);
free(n);
n = NULL;
}
void deleteList(struct node** head_ref)
{
struct node* current = *head_ref;
struct node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
*head_ref = NULL;
}
Try like this ....you can change names as you want. If you still need help let me know.
Head has been freed when this functions ends but it's not null. Everything in C is passed by value. So you pass a copy of the location of head into destroy. That memory is deallocated but head is not changed.
You could write this as:
destroy(&head);
void destroy(struct node** n){
if(!*n) return;
destroy(&((*n)->next));
free(*n);
*n = NULL;
}
You have to use a pointer pointing to your list, calling with destroy(&n):
// clear complete list
void destroy(struct node **n)
{
if (*n == NULL)
return;
if ((*n)->next == NULL)
{
free(*n);
*n= NULL;
return;
}
struct node *iter = *n;
struct node *prev = NULL;
// get last item and the previous one
while (iter->next != NULL)
{
prev = iter;
iter = iter -> next;
}
prev->next = NULL;
free(iter);
destroy(n);
}
Hope this may help you.
Your recursive destroy function cannot modify the head variable in the caller's frame.
The statement n = NULL only affects the function argument, which is a local variable of the destroy function. It actually has no effect, so you can remove this statement.
You should set the head to NULL after the call to destroy in the caller function if it is needed there.
Here is the sample function to destroy Linked list using DeleteRear():
void Destroy_Using_Rear(List *L)
{
int y;
Node *P,*Q,*Z;
while(P!=NULL){
y=DeleteRear(L,x);
return y;
Z=P;
P=*L;
}
}
Related
I am having a problem with the free() function of C's stdlib, of my knowladge this function can only delete a given node of the linked list at a time, how can i use this function to delete an entire circular linked list ?
Do I have to make a pointer pointing to the head of the circular linked list and beguin to free node by node with the care to make each pointer from one node tho the next, be taken to point to NULL before i can free that node ? and if so how do I free the head node ?
You could theoretically, re-alloc the whole heap memory of a list and pass it to a free function.
However the most secure way to clean up a linked list is to iterate and free , each node.
This is an example of a destructor function.
void destroy_link_list(linked_list_t** link_list)
{
node_t* head = (*link_list)->start_node;
while(head != NULL)
{
node_t* temp = head->next;
free(head->data_list);
head->data_list = NULL;
free(head);
head = temp;
}
(*link_list)->start_node = NULL;
free(*link_list);
*link_list = NULL;
}
This linked list looks like this
typedef struct node node_t;
struct node
{
int unique_id;
node_t* next;
void* data_list;
};
typedef struct linked_list
{
int num_nodes;
node_t* start_node;
}linked_list_t;
So this is how to delete an entire Circular Linked List:
node* clear(node *n){
if (n->next == head){
free(n);
n = NULL;
return n;
}
n->next = clear(n->next);
free(n);
n = NULL;
return n;
}
Call function as:
head = clear(head);
Why does this not work ?
void freePolinomial(Polinomial p){
Polinomial before, after;
after = p -> aft;
do{
before = after;
after = after->aft;
before->aft = NULL;
free(before);
}while(after != NULL && (after->index) != -1);
p=NULL;
after->aft = NULL;
free(after);
}
where each node has an index and the head node has -1 as an index.
I must write a function DeleteList() that takes a list, deallocates all of its memory and sets its head pointer to NULL (the empty list).
It seems to work, but idk if it truly works because the way in which I implemented (which I assume is the wrong way) is very different than the one in the solution. I assume it only deletes a few nodes or there is an issue with the memory management.
int Length(struct node* head)
{
int count = 0;
struct node* current = head;
while (current != NULL)
{
count++;
current = current->next;
}
return(count);
}
void DeleteList(struct node** headRef)
{
int len = Length(*headRef);
for(int i = 0;i<len;i++)
free(*headRef);
*headRef = NULL;
}
You are not actually freeing the whole linked list but you are freeing head node repeatedly. I would suggest you to use below approach.
void DeleteList(struct node** headRef) {
struct node *ptr = *headRef;
struct node *temp = NULL;
while(ptr)
{
temp = ptr;
ptr = ptr->next;
free(temp);
}
*headRef = NULL;
}
I am having a tough time deleting all members in a linked in a single function. If I break it up like you see below, it works fine, but this seems wildly inefficient and want to figure out the correct way to do this. in order to free all nodes I need to have function to first free all nodes other then the head, then have a function free the head link. this seems like it would be easy to do but I am having trouble.
Thanks for the help!
int main() {
struct node *head = NULL;
createList(&head);
//do stuff with list
freeListMembers(head);
freeListHead(&head);
return 0;
}
int createList(struct node **head) {
//create list
return 0;
}
void freeListMembers(struct node *head){
while(head->next != NULL){
head->next = NULL;
free(head->next);
}
return;
}
void freeListHead(struct node **head) {
*head = NULL;
free(*head);
return;
}
here is the code that I want to work but does not. the issue I am seeing is a an error for "*head->next;" where it sais "expression must have pointer to struct or union type"
int main() {
struct node *head = NULL;
createList(&head);
//do stuff with list
freeAllListMembers(&head);
return 0;
}
int createList(struct node **head) {
//create list
return 0;
}
void freeAllListMembers(struct node **head){
while (head != NULL) {
struct node *temp = *head->next;
free(*head);
*head = temp ;
}
return;
}
From your code :
void freeListMembers(struct node *head){
while(head->next != NULL){
head->next = NULL;
free(head->next);
}
return;
}
This is freeing NULL, not your node*.
Freeing the list is as simple as using a temporary pointer to the next node.
while (head) {
node* next = head->next;
free(head);
head = next;
}
From your edit :
void freeAllListMembers(struct node **head){
while (head != NULL) {
struct node *temp = *head->next;
free(*head);
*head = temp ;
}
return;
}
There are a couple errors with this. It should be while (*head != NULL) and (*head)->next. The first is a logic error, because head will always be non-NULL, and the second is a syntax error, because you need to dereference the head pointer before accessing the next pointer.
This will work. You just set next of head to null and freed head. Now we can not move to second element.So we wont be able to free the nodes.Also check base condition. I hope it helps
void freeListmembers(node *head){
node *temp=head;
if(head==NULL)//Base condition
return;
while(head->next!=NULL){
temp=head;//Moved temp to head. we will move head to next and free the previous node
head=head->next;
free(temp);
}
free(head);
return;
}
I am working with linked lists and i fill the structure but when I delete the whole structure and try to print the contents of the linked list (should be null), a list of numbers appear. I know it is probably a memory problem. Any suggestions of how to fix it?
Code for deleting whole linked list:
void destroy(set_elem *head)
{
set_elem *current = head;
set_elem *next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
head = NULL;
}
While your delete function works correctly, it doesn't set the head in the caller to NULL when you do head = NULL; as you are only modifying a local pointer, which causes to your later logic where you are trying to print the values by checking the value of head.
To modify the original pointer, pass a pointer to head and set *head=NULL;
void destroy(set_elem **head)
{
set_elem *current = *head;
/* rest is the same */
*head = NULL;
}
when you copy head pointer passed into the function, head node is unaffected. You have to pass reference to the pointer to the head,then you will be able to delete head pointer. This can be also done by passing a pointer to the pointer to the head of the linked list but I find passing a reference more convenient. Following are the changes to your code.
void destroy(set_elem*& head)
{
set_elem* current = head;
set_elem* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
*head = NULL;
}
You are not changing the original head. You should pass the pointer to this head i.e. pointer to a pointer or should return changed head to the caller. Following is the code to return changed head to the caller. There are other answers showing pointer to pointer approach.
set_elem* destroy(set_elem *head) {
set_elem *current = head;
set_elem *next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
head = NULL;
return head;
}
in caller,
head = destroy(head);
You're modifying only the local head pointer
Use a double pointer to modify the head, which would be later used for printing/processing
void destroy(set_elem** head)
{
set_elem* current = *head;
set_elem* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
*head = NULL;
}
I have a weird problem. I have this piece of code, but it doesn't work. The weird part is that inside the function, the list is changed (printf commands indicate this), but when call this function, nothing will be added to the list (my list is not empty).
void pushToList(node* list, int val) {
node* newNode = (node*) malloc(sizeof(node));
newNode->value=val;
newNode->next = list;
list = newNode;
printf("here, list->value = %d \n", list->value);
printf("here, list->next->value = %d \n", list->next->value);
}
// ----------------------------------
// if (list==NULL) {
// newNode->next = NULL;
// list = newNode;
// } else {
// newNode->next = list;
// list = newNode;
// }
I call this function for example in my main function like this:
node* node1;
pushToList(node1, 1111);
And here is my struct and typedef in a separate header file (that I have included in my function file):
#ifndef STACKELEMENT_H
#define STACKELEMENT_H
struct stackElement {
int value;
struct stackElement* next;
};
typedef struct stackElement node;
#endif /* STACKELEMENT_H */
Another weird behavior is that I have the following function for appending an item, and this function only works if my list is not empty:
int appendtoList(node* head, int val) {
node* current = head;
node* newNode = (node*) malloc(sizeof (node));
if(newNode == NULL){
fprintf(stderr, "Unable to allocate memory for the new node\n");
exit(-1);
}
newNode->value = val;
newNode->next = NULL;
while (current->next) {
current = current->next;
}
current->next = newNode;
// if (head->next == NULL) {
// head->next = newNode;
// } else {
// while (current->next != NULL) {
// current = current->next;
// }
// current->next = newNode;
// }
//
return 0;
}
use node**list as argument type in your function.
when u pass a pointer to a function like struct node *x to
void max (struct node*p);
the pointer is passed by value AND
if u want to really manipulate the contents to which x points to use struct node** as the argument type and pass &x to the function.
Same logic should apply to your problems.
The problem was with the return type, i.e. the scope of a variable which in this case is a pointer variable. mbratch also pointed out this, thank you very much, but actually before reading mbratch's comment, I suddenly remembered a point from a lecture note about "accessing an object outside of its lifetime" which I think is different from "call by value/call by reference" problem.
Just some clarifications for people who may run into this problem and may get confused:
since we are allocating memory for the struct newNode INSIDE the function pushToList (even though using dynamic memory allocation command), the memory assigned to this variable would be free/destroyed when the function ends and the control returns back to the callee function (in this case, main()). So you should set the return type of your function to node* (a pointer to a node struct) and in your function return the head. Like this:
node* pushToList(node* head, int val) {
node* newNode = (node*) malloc(sizeof(node));
newNode->value=val;
newNode->next = head;
head = newNode;
return head;
}
In appendToList function, in addition to this mistake, as mbracth pointed out, I was doing another mistake by checking head->next (although implicitly) rather than head itself (to see if it's NULL): if head is NULL, you can not access head->next. Indeed two answers marked as the correct answers in some other posts here on stackoverflow misleaded me to this mistake. Anyway, here is the correct way:
if (head == NULL) {
head = newNode;
} else {
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}