Program keeps crashing when I destroy my linked list - c

For some reason, my code keeps crashing.
If anyone can help me find out why, I would be very thankful.
int destroy(struct node *p)
{
struct node * temp = p;
struct node * next;
while (temp->next != NULL)
{
next = temp->next;
free(temp);
temp = next;
}
p = NULL;
return 1;
}

You need to test temp for null-ness, not temp->next:
void destroy(struct node *p)
{
struct node *temp = p;
while (temp != NULL)
{
struct node *next = temp->next;
free(temp);
temp = next;
}
}
You also don't need to set p to null (it doesn't do anything useful). And returning a status is not a good idea. Your callers either have to test it (but will never see anything other than 1, so the test is pointless), or they have to ignore it (in which case, why bother to return it?). You could do without the variable temp, too:
void destroy(struct node *list)
{
while (list != NULL)
{
struct node *next = list->next;
free(list);
list = next;
}
}
If you really want to set the pointer to null, you have to change the notation:
void destroy(struct node **list)
{
struct node *node = *list;
while (node != NULL)
{
struct node *next = node->next;
free(node);
node = next;
}
*list = NULL;
}
and instead of:
struct node *root = ...;
...
destroy(root);
you would have to write:
struct node *root = ...;
...
destroy(&root);

Related

Linked list implementation in C(printing only last two nodes)

#include <stdlib.h>
#include <stdio.h>
struct node {
int data;
struct node *next;
};
void addLast(struct node **head, int value);
void printAll(struct node *head);
struct node *head1 = NULL;
int main() {
addLast(&head1, 10);
addLast(&head1, 20);
addLast(&head1, 30);
addLast(&head1, 40);
printAll(head1);
return 0;
}
void addLast(struct node **head, int value) {
struct node *newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = value;
if (*head == NULL) {
*head = newNode;
(*head)->next = NULL;
} else {
struct node **temp = head;
while ((*temp)->next != NULL) {
*temp = (*temp)->next;
}
(*temp)->next = newNode;
newNode->next = NULL;
}
}
void printAll(struct node *head) {
struct node *temp = head;
while (temp != NULL) {
printf("%d->", temp->data);
temp = temp->next;
}
printf("\n");
}
addLast() will append the new node at the end of the list, with printAll(), I am printing entire list.
Every time when I am printing the list, I can only see the last two nodes.
Can anyone please help, why loop is not iterating over entire list ?
The function addLast is too complicated and as result is wrong due to this statement
*temp = (*temp)->next;
in the while loop. It always changes the head node.
Define the function the following way
int addLast( struct node **head, int value )
{
struct node *newNode = malloc( sizeof( struct node ) );
int success = newNode != NULL;
if ( success )
{
newNode->data = value;
newNode->next = NULL:
while( *head ) head = &( *head )->next;
*head = newNode;
}
return success;
}
Take into account that there is no need to declare the variable head1 as global. It is better to declare it inside the function main.
Also all the allocated memory should be freed before exiting the program.

Reversing a Linked List using recursion in C

I'm fairly new to C and I am trying to create a function to reverse a linked list, passing only the List itself as a parameter. Is this possible to do without passing a node as a parameter?
Here is my code so far, I know it does not work correctly because I cannot figure out how to make the recursive call on the rest of the list.
void reverse(LL_t *L) {
if (L->head->next == NULL) {
return;
}
node_t *rest = L->head->next;
reverse(rest);
node_t *q = rest->next;
q->next = rest;
rest->next = NULL;
}
As well here are my type definitions.
typedef struct {
node_t *head;
node_t *tail;
} LL_t;
typedef struct _node {
int data;
struct _node *next;
} node_t;
You can reverse the list with a simple loop, recursion is not needed and given your API, not appropriate.
Here is a modified version of your function:
void reverse(LL_t *L) {
node_t *prev = NULL;
node_t *curr = L->head;
L->tail = curr;
while (curr != NULL) {
node_t *next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
L->head = prev;
}
If you are required to use recursion, you can test if the list is empty or limited to a singleton and do nothing, otherwise remove the head element, reverse the resulting list and append the element to the end:
void reverse(LL_t *L) {
if (L->head != L->tail) {
/* at least 2 elements */
node_t *node = L->head;
L->head = node->next;
node->next = NULL;
reverse(L);
L->tail = L->tail->next = node;
}
}
Note that this recursive approach may have undefined behavior if the list is too long as reverse will recurse too many times and cause a stack overflow.
struct node {
int value;
struct node* next;
};
Non-recursive definition operating in constant stack space:
void reverse(struct node** ptr) {
struct node* prev_ptr;
struct node* node_ptr;
if (prev_ptr = * ptr) {
node_ptr = prev_ptr -> next;
prev_ptr -> next = NULL;
while (node_ptr) {
struct node* temp = node_ptr -> next;
node_ptr -> next = prev_ptr;
prev_ptr = node_ptr;
node_ptr = temp;
}
* ptr = prev_ptr;
}
}
Extensionally equivalent recursive definition:
void reverse(struct node** ptr) {
struct node* node_ptr;
if (node_ptr = * ptr) {
node_ptr -> next = NULL;
* ptr = reverse_rec(node_ptr, node_ptr -> next);
}
}
struct node* reverse_rec(struct node* prev_ptr, struct node* node_ptr) {
if (! node_ptr) { return prev_ptr; }
struct node* temp = reverse_rec(node_ptr, node_ptr -> next);
node_ptr -> next = prev_ptr;
return temp;
}
This works, but using recursion to reverse a list requires O(n) stack space overhead. The concept here is to advance the static instance of L->head, while keeping a local copy of head for each level of recursion. Recursion continues until the end of the list is reached, then the list is reversed using the local instances of head as reverse() returns backup the call chain.
void reverse(LL_t *L)
{
node_t *head;
if(L->head == NULL || L->head->next == NULL)
return;
head = L->head;
L->head = head->next;
reverse(L);
head->next->next = head; // reverse the nodes
head->next = NULL;
L->tail = head; // ends up setting tail to what was 1st node
}
//A simple program to reverse a Linked List
void reverse(struct node* head_ref)
{
struct node* first;
struct node* rest;
if (head_ref == NULL)
return;
first = head_ref;
rest = first->next;
if (rest == NULL)
return;
reverse(rest);
first->next->next = first;
first->next = NULL;
head_ref = rest;
}

Insert an element in end of a singly Linked List

I have been trying to fix this code since morning but could get it done. So, finally i need some help in figuring out the error. The code compiles with no error but when i run it from terminal i get an error saying "segmetation error: 11"
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node *next;
};
struct Node *head;
void Insert(int data);
void Print();
int main()
{
head = NULL; //list is empty
Insert(3);
Insert(5);
Insert(2);
Insert(8);
Print();
return 0;
}
void Insert(int data)
{
struct Node *temp = malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
struct Node *temp1 = head;
while(temp1 != NULL)
{
temp1= temp1->next;
}
temp1->next = temp;
}
void Print()
{
struct Node *temp =head;
while(temp != NULL)
{
temp = temp->next;
printf("%d", temp->data);
}
}
You never set head to anything other than NULL.
(Even if you fix the above) temp1 is guaranteed to be NULL by the time you get to temp1->next = temp;.
P.S. I don't think it's such a great practice to call you variables temp, temp1 etc. From those names it is impossible to tell what their supposed function is.
Usually single linked lists have an inserting operation that inserts data at the beginning of the list. Nevertheless your function insert can look the following way
void Insert( int data )
{
struct Node *temp = malloc(sizeof( struct Node ) );
temp->data = data;
temp->next = NULL;
if ( head == NULL )
{
head = temp;
}
else
{
struct Node *current = head;
while ( current->next != NULL ) current = current->next;
current->next = temp;
}
}
It would be better if you check in the function whether the node was allocated.
Function Print also is wrong. It can look like
void Print( void )
{
for ( struct Node *current = head; current != NULL; current = current->next )
{
printf( "%d ", current->data );
}
}
You are writing
while(temp1 != NULL)
Make it like this
while(temp1->next != NULL)
Here, temp1 points to null at the end of loop, and you are trying to add node after null i.e.
null->next =temp;
which must be throwing error.
struct Node *curr;
void Insert(int data){
struct Node *temp = malloc(sizeof(struct Node));
temp->data = data;
temp->next =NULL;
if(head == NULL)
curr = head = temp;
else
curr = curr->next = temp;
}
void Print(){
struct Node *temp =head;
while(temp != NULL){
printf("%d ", temp->data);
temp=temp->next;
}
}

trouble updating tail pointer in queue adt using singly linked list

i am trying to make a queue library that is based on a linked list library i already made. specifically i am having troubles updating the tail pointer in the queue structure after i add a new node to the linked list.
linked list structure:
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
queue structure:
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
so here is my add function in the queue library
void add(queue currentQueue, int data){
addTail(currentQueue.list, data, data+5);
currentQueue.back = currentQueue.back->next;
}
and the addTail function from the linked list library
void addTail (node *head, int value, int length) {
node *current = head;
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
while (current->next != NULL)
current = current->next;
newNode->next = NULL;
current->next = newNode;
}
so again my problem is the tail pointer is not getting set to the last node in the list. it is remaining in the same place as the head pointer. ive been researching this for hours trying to see if im just missing something small but i cant find it. if more code or explanation is needed to understand my problem i can provide it.
how a queue is created:
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
node *initNode (int value, int length){
node *newNode = NULL;
newNode = (struct listNode *)malloc(sizeof(node));
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
return newNode;
}
void add(queue currentQueue, int data){
You are passing a copy of the queue struct to add, so only the copy's members are changed. You need to pass a queue* to the function to be able to change the members of the queue itself.
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
and call it as add(&your_queue);
In your addTail function, you should check whether head is NULL too.
And with
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
in addTail, you have a serious problem. With the assignment newNode = initNode(value, length);, you are losing the reference to the just malloced memory.
If initNode mallocs a new chunk of memory, it's "just" a memory leak, then you should remove the malloc in addTail.
Otherwise, I fear initNode returns the address of a local variable, à la
node * initNode(int val, int len) {
node new;
new.nodeValue = val;
new.nodeLength = len;
new.next = NULL;
return &new;
}
If initNode looks similar to that, that would cause a problem since the address becomes invalid as soon as the function returns. But your compiler should have warned you, if initNode looked like that.
Anyway, without seeing the code for initNode, I can't diagnose the cause.
But if you change your addTail to
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
it should work.
However, since you have pointers to the first and the last node in the list, it would be more efficient to use the back pointer to append a new node,
void add(queue *currentQueue, int data){
node *newNode = malloc(sizeof *newNode);
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = data;
newNode->nodeLength = data+5;
newNode->next = NULL;
currentQueue->back->next = newNode;
currentQueue->back = newNode;
}
since you needn't traverse the entire list to find the end.
A simple sample programme
#include <stdlib.h>
#include <stdio.h>
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
int main(void) {
queue myQ = createQueue(10);
for(int i = 1; i < 6; ++i) {
add(&myQ, i);
printf("list: %p\nfront: %p\nback: %p\n",
(void*)myQ.list, (void*)myQ.front, (void*)myQ.back);
}
node *curr = myQ.front->next;
while(curr) {
printf("Node %d %d, Back %d %d\n", curr->nodeValue,
curr->nodeLength, myQ.back->nodeValue, myQ.back->nodeLength);
curr = curr->next;
}
while(myQ.list) {
myQ.front = myQ.front->next;
free(myQ.list);
myQ.list = myQ.front;
}
return 0;
}
works as expected, also with the alternative add implementation.
i think you never initialized back, so back->next is some random pointer?

Want to make linked list function that deletes first Node

This is my code. I made three functions for adding a new node, inserting a new node between two others, and one deleting, but I dont know how to delete the first node. I dont even have any idea.
#include <stdlib.h>
#include <stdio.h>
struct Node
{
int data;
struct Node *next;
};
void insert(Node* insertafter, Node* newNode);
void add(Node* llist,Node* newNode);
void deleteafter(Node *llist);
void deletefirts();
int main()
{
struct Node *llist;
struct Node *newNode;
newNode = (Node*)malloc(sizeof(struct Node));
newNode->data = 13;
struct Node *newNode2;
newNode2 = (Node*)malloc(sizeof(struct Node));
newNode2->data = 14;
llist = (Node*)malloc(sizeof(struct Node));
llist->data = 10;
llist->next = (Node*)malloc(sizeof(struct Node));
llist->next->data = 15;
llist->next->next = NULL;
insert(llist,newNode);
add(llist,newNode2);
if(llist->next == NULL)
printf("shecdoma");
struct Node *cursor = llist;
while (cursor != NULL)
{
printf("%d\n", cursor->data);
cursor = cursor->next;
}
system("pause");
return 0;
}
void insert(Node* insertafter, Node *newNode)
{
newNode->next = insertafter->next;
insertafter->next = newNode;
}
void add(Node* llist,Node *newNode)
{
if(llist->next == NULL)
{
llist->next = newNode;
newNode->next = NULL;
}
else
{
while(llist->next != NULL)
{
llist = llist->next;
}
add(llist,newNode);
}
void deleteafter(Node *llist)
{
if(llist->next != NUll)
llist->next = llist->next->next;
}
void deletefirst();
{
}
You can use something like:
void deletefirst (struct Node **head) {
struct Node *tmp = *head; // save old head for freeing.
if (tmp == NULL) return; // list empty? then do nothing.
*head = tmp->next; // advance head to second node.
free (tmp); // free old head.
}
You pass in the pointer to the head so that you can change it. Deleting nodes other than the first does not require this but deleting the first node does.
You set up a temporary pointer to the head so you free it, then you change the head to point to its next element. Then you free the old head and return.
void deleteFirst(Node** list)
{
Node* temp = *list;
if (*list != NULL)
{
*list = (*list)->next;
free(temp);
}
}

Resources