C Linked List copy segfault - c

I am rather new to C, and am working on copying a Linked List. It seg faults somewhere in the while loop, I think I am having some pointer troubles. Also, I'm not sure if I need to malloc each 'next' node. Do I? It makes sense for me to have to.
struct node* copyList() {
struct node* walker = head; // starting point to "walk" the list
struct node* temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->data = walker->data;
while( walker != NULL ){ // done when we reach the node pointing to NULL
walker = walker->next; // advance walker to the next node in the list
temp = temp->next;
temp = (struct node*)malloc(sizeof(struct node));
temp->data = walker->data;
}
return walker;
}
The node strut is as follows
struct node {
int data;
struct node* next;
};

Suppose you reach last node..
Now inside loop , you increment walker..so now walker = NULL..
so this statement gives an error temp->data = walker->data..
Also you are just creating nodes and copying data not connecting your new linked list..
You need to maintain new Head pointer to return at the end
Keep reference to previous node so that you can link it to current node
Update the pointers
Change it along the lines of this..
struct node* copyList() {
struct node* walker = head; // starting point to "walk" the list
struct node* newHead=NULL,temp,prev=NULL;
while( walker != NULL ){ // done when we reach the node pointing to NULL
temp = (struct node*)malloc(sizeof(struct node)); //create new node
temp->data = walker->data; //copy data
if(prev==NULL) //if its first node
newHead = temp; //new head pointer
else
prev->next = temp; //else link to previous node
prev = temp; //update pointers
walker = walker->next;
}
return newHead;
}

Just where do you expect the value of temp->next in your loop to come from?
Also, to get a bit more meta, you might be vastly better off using e.g. std::list in C++ rather than implementing your own data structures like this. Even for experienced engineers, such efforts are notoriously error-prone.

Related

C Implementation of linkedlist

I am trying to print the values stored in a linked list but i'm running into a infinite loop.Please could some one tell me what is wrong with my code. I am able to successfully collect the data of the nodes but when printing the list i run into a continuous loop. Any help would be greatly appreciated. Thanks in advance
#include <stdio.h>
#include <stdlib.h>
struct node {
int data; //4 bytes
struct node *next; // 4bytes 32 bit and 8 bytes i 64bit cp
};
int main(){
struct node *head,*newnode,*temp;
head = NULL ;
temp = head;
int count=0, choice=1;
while(choice){
newnode = (struct node *)malloc(sizeof(struct node));
printf("Enter data:");
scanf("%d",&newnode-> data);
newnode->next = head;
if(head == 0){
head = temp = newnode;
}
else{
temp->next = newnode;
temp = newnode;
}
printf(" %d ",temp->data);
printf("Do you want to continue? 0/1");
scanf("%d",&choice);
}
int i = 0;
temp = head;
while( temp!=NULL){
printf("%d ",temp->data);
temp=temp->next;
}
}
I doubt it's within the scope of the homework problem in question, but it's really helpful to break linked list tasks down into smaller problems.
We start with this node definition:
struct node {
int data; //4 bytes
struct node *next; // 4bytes 32 bit and 8 bytes i 64bit cp
};
Which I'm going to typedef to make my life slightly easier.
typedef struct node {
int data; //4 bytes
struct node *next; // 4bytes 32 bit and 8 bytes i 64bit cp
} node_t;
Let's find the last node for a given head. We'll create a node_t pointer called current and use it to walk the list until it's at the last node. We'll know it's the last because its next member will be NULL. Of course, if head is NULL, then we'll just return NULL immediately.
node_t *last_node(node_t *head) {
if (head == NULL) {
return NULL;
}
node_t *current;
for (current = head; current->next != NULL; current = current->next);
return current;
}
Now, let's add a value to a list with a given head. We can provide a shortcut by returning a pointer the new last node. We'll also short-circuit a lot of work if head is NULL.
Otherwise we'll get the last node using the last_node function we defined, set its next to the new node, and return a pointer to the new node.
node_t *add_to_list(node_t *head, int value) {
node_t * new_node = malloc(sizeof(node_t));
new_node->data = value;
new_node->next = NULL;
if (head == NULL) {
return new_node;
}
node_t *last = last_node(head);
last->next = new_node;
return new_node;
}
And finally we can write a function to print the list. Given that you've already seen walking the list, this should look pretty familiar.
void print_list(node_t *head) {
for (node_t *current = head;
current->next != NULL;
current = current->next) {
printf("%d ", current->data);
}
}
Breaking down big problems into smaller problems is crucial. Practice it!
When you create a new node, you set it's "next" node to the head node. That's how the loop is made.
Set it to NULL.
And afterwards you set the new node as the "current node's next node" and the "current node" as well.
I believe you wanted to set it to temp's next node and then move the temp onto it's next node.
Also please don't compare head with 0... If you expect it to be NULL compare to NULL.

Why use double pointer when inserting node in sorted order in linkedlist?

typedef struct node node;
struct node {
int data;
node *next;
};
int insert_asc(node **phead, int data) {
node **traser;
node *newnode = malloc(sizeof(node));
if (newnode == 0)
return 0;
newnode->data = data;
for (traser = phead; *traser != 0; traser = &(*traser)->next)
if (data <= (*traser)->data)
break;
newnode->next = *traser;
*traser = newnode;
return 1;
}
The confusing part for me is when you dereference a double pointer traser.
how come (*traser)->next holds the next node's address?
and what exactly is *traser here?
Double pointers are used in the posted code for two separate purposes:
node **phead: the head of the list is passed by referenced so it can be updated by insert_asc if the new node must be inserted at the head of the list. Passing by reference is not possible in C, the idiomatic way to achieve it is to pass a pointer to the value to be updated by the function, hence a double pointer phead.
node **traser: To avoid making a special case of the empty list and the insertion at the head of the list, the programmer uses a pointer to keep track of the place to insert the new node. traser first points to the head of the list which in this case is the value of phead and is updated to point to the link between nodes, the next member of the current node, when it is determined that the new node must be inserted after the current one. This is an elegant way to implement insertion without a special case. C allows thanks to pointers, it is not possible in java nor javascript because these language do not have generalised pointers.
Note however that the code could be make more readable by use NULL instead of 0 when comparing pointers:
typedef struct node node;
struct node {
int data;
node *next;
};
int insert_asc(node **phead, int data) {
node **traser;
node *newnode = malloc(sizeof(node));
if (newnode == NULL)
return 0;
newnode->data = data;
for (traser = phead; *traser != NULL; traser = &(*traser)->next) {
if (data <= (*traser)->data)
break;
}
newnode->next = *traser;
*traser = newnode;
return 1;
}
Note also that new nodes with a given value of data are inserted before nodes with the same data value. It does not make a difference in this case and may be a little faster for lists with many duplicates, but if the payload was more elaborate, this insertion method would implement a non-stable sort, whereas using < instead of <= would make the sort stable.
For illustration, here is alternative implementation that does not use a double pointer for the insertion point and needs extra tests for the special cases:
int insert_asc(node **phead, int data) {
node *cur;
node *newnode = malloc(sizeof(node));
if (newnode == NULL)
return 0;
newnode->data = data;
cur = *phead;
if (cur == NULL || cur->next == NULL) {
newnode->next = cur;
*phead = newnode;
} else {
while (cur->next != NULL && data < cur->next->data)
cur = cur->next;
newnode->next = cur->next;
cur->next = newnode;
}
return 1;
}
You are using a double pointer here in order to keep track of the head of your list.
If you were using a simple pointer here and exchanged the nodes, you would risk loosing the address of some nodes of your list.
This is because if you were passing a simple pointer to the head of your list, you would then manipulate a copy of you head address in your function, therefore when you exchange positions in your function, the address of your head would still be the same, if you exchanged the head with another node, then the address of all nodes before the old head would be lost after your function modifies your list.
Edit: pythontutor.com is a tool that helped me understanding the behavior of linked list quite easily thanks to its excellent visualization tool, I would highly recommend you to use it.

trying to understand this linkedlist insertion code

i have this code
struct Node {
int data;
struct *Node next;
};
struct Node *head;
void insert(int x) {
node* temp = (node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = head;
head = temp;
}
int main()
{
head = NULL;
}
I'm following this video, It looks like the code works. I'm having a hard time putting it together though.
we have a node head which is initially set to NULL in the main method.
The linkedlist holds an int and next. This insert code sets data to an int and next to head. Then it sets head to temp.
Wouldn't this make give head the int and then make it point to itself over and over again since we set temp.next to head and then head = temp ?
So far I've only done iterations on linkedlist where the last next is NULL.
This code inserts an item at the beginning of a linked list - it creates a new node, sets its data, and makes its next point to the current head.
No.
node* temp = malloc(sizeof(struct node));
temp->data = x;
We have a new node, and have set its value.
temp->next = head;
The head (if any) will come after this element in the list. That means this should be our new head.
head = temp;
And now it is.
If head was NULL, this list has no next entry, as expected.
If head was not NULL, this node is the new head, and its next points to the second element in the list (the old head).

Writing a proper push() function for a singly-linked list.

http://cslibrary.stanford.edu/103/
Please find some time to go through the wrong push function in this linked list basics document. I just followed the same implementation of this function. So according to the document the addition of data to the head of the list shouldn't happen. But mine works perfectly fine with the way they said it has to be implemented. I am very confused about finding out what the problem is?
Here is the code:
#include<stdio.h>
#include<stdlib.h>
struct node{
int data;
struct node * next;
};
typedef struct node Node; /* Utilize a typedef for Node rather than typing
struct Node everytime we declare a node. */
Node* BuildOneTwoThree() {
Node* head =NULL; // pointer called head.
Node* second =NULL; // pointer to second memory block
Node* third = NULL; // pointer to third memory block
head = (Node*)malloc(sizeof(Node)); //allocate a memory block of size node
//in the heap and head pointer will
//point to this memory.
second = (Node*)malloc(sizeof(Node)); //allocate a memory block of size node
//in the heap and second pointer will
//point to this memory
third = (Node*)malloc(sizeof (Node)); //allocate a memory block of size node
//in the heap and third pointer will
//point to this memory
head->data = 1;
head->next = second; //the next pointer of node type will point to another
//pointer of node type which is second!!
second -> data = 2;
second -> next = third;
third -> data = 3;
third -> next = NULL;
return head;
}
Node* WrongPush(Node* head, int data) {
Node* newNode = malloc(sizeof(Node));
newNode->data = data;
newNode->next = head;
head = newNode; // NO this line does not work!
return head;
}
Node* WrongPushTest() {
Node* head = BuildOneTwoThree();
Node* current = WrongPush(head, 4);
return current;
}
int main(){
Node* ptr = WrongPushTest(); //My question is why does the wrong push
//test implementation that I setup work?
while(ptr!=NULL) {
printf("%d\n",ptr->data);
ptr=ptr->next;
}
}
The first thing I notice is that you actually changed the implementation as written in the document you referenced. The document implements WrongPush as follows (which I modified to use your structure definition):
void WrongPush (Node * head, int data) {
Node * newNode = malloc(sizeof(Node));
newNode->data = data;
newNode->next = head;
head = newNode; /* This will not work because you are not
modifying head in the calling function. */
}
The problem with your implementation is that it is not easily scalable. For example, using your code, try WrongPushTest as follows:
Node * WrongPushTest() {
Node * head = BuildOneTwoThree();
Node * current = WrongPush(head, 4);
current = WrongPush(head, 5);
current = WrongPush(head, 6);
}
The output will not be something that the programmer had intended. The goal is to have a push function that utilizes the original head without having to create a new node everytime you push another node onto the linked list. The example they use in the document is as follows:
void Push(Node** headRef, int data) {
Node * newNode = malloc(sizeof(Node));
newNode->data = data;
newNode->next = *headRef;
*headRef = newNode;
}
Notice that I am not returning a pointer to the newly created head as was done in your example. The above allows us to always push a new node onto the head of the original linked list by directly manipulating the original head pointer.
Node * PushTest() {
Node * head = BuildOneTwoThree();
Push (&head, 4);
Push (&head, 5);
Push (&head, 6);
return head;
}
Hopefully this helps to clear things up for you!

Copying a linked list- crashes the program

I have the following C code to copy a linked list(taken from Stanford CS Library files):
struct Node* CopyList(struct Node* head)
{
struct Node* current = head;
struct Node* newList= NULL;
struct Node* tail= NULL;
while (current !=NULL)
{
if(newList==NULL)
{
newList=malloc(sizeof(struct Node));
newList->data=current->data;
newList->next=NULL;
tail= newList;
}
else
{
tail= malloc(sizeof(struct Node));
tail= tail->next;
tail->data=current->data;
tail->next = NULL;
}
current= current->next;
}
return(newList);
}
I have the following as a part of my main function:
struct Node* head = NULL;
for (i=3; i >=1;i--) //insert 3 elements into the linked list
{ //push inserts elements in the front
Push(&head,i);
} //now a linked list 1->2->3->NULL is formed
struct Node* newlst= CopyList(head); // copies contents into a new linked list
I am compiling the code using Bloodshed Dev C++. I don't get any compilation errors but when I run it, it just crashes. What could be the issue with this? Am I passing the right parameter to the CopyList function?
Your problem lies here, in the else bit:
tail = malloc (sizeof (struct Node));
tail = tail->next;
tail->data = current->data;
tail->next = NULL;
You are allocating a new node and setting tail to point to it (in that first line). Then you are using tail as if it's the old tail. Specifically, that second line will give you a rogue pointer (as you haven't initialised the new node with valid pointers), which will probably crash in the third line when you try to dereference it.
You need something like:
// First, set up the new node.
newList = malloc (sizeof (struct Node));
newList->data = current->data;
newList->next = NULL;
// Then, adjust the tail pointers.
tail->next = newList;
tail = newList;
Actually, looking back at your code, what you probably intended was:
tail->next = malloc (sizeof (struct Node)); // use tail->next, not tail.
tail = tail->next;
tail->data = current->data;
tail->next = NULL;
which achieves the same result.
I suppose I should mention that you really ought to check the return values from malloc in case you run out of memory. You can do this with something like:
tail->next = malloc (sizeof (struct Node)); // use tail->next, not tail.
if (tail->next == NULL) {
// do something here for recovery.
return;
}
// Only continue here if the allocation worked.
tail = tail->next;
tail->data = current->data;
tail->next = NULL;
Without checks like that, you will get crashes when you run out of memory.
You are allocating memory for tail, it should be tail->next. Without this you would lose previous pointers.
Modified code
struct Node* CopyList(struct Node* head)
{
//.... same as before
while (current !=NULL)
{
if(newList==NULL)
{
//.... same as before
}
else
{
tail->next = malloc(sizeof(struct Node));
tail= tail->next;
tail->data=current->data;
tail->next = NULL;
}
current= current->next;
}
return(newList);
}
Shash
If it just dies, that is usually a sing of accessing an invalid pointer. Most likely a null pointer.
Here is your problem:
tail= malloc(sizeof(struct Node));
tail= tail->next;
tail points to an unitialised area of memory. So tail->next may be anything.
Try
tail->next= malloc(sizeof(struct Node));
tail= tail->next;
Consider this line -
tail = tail->next;
When you are creating the first node in the new list, it's OK, both the newList and tail points to that node.Now think what will happen when a second node will be created in the new list -
tail = malloc(sizeof(struct Node)); // tail points to the new node
tail = tail->next; // You are assigning new node's next to tail, but
// did you initialize next to anything?
So next isn't initialized to anything, and you are assigning it to tail, so tail now contains garbage. When you are assigning it some value in the next two lines, your program will certainly crush.
Instead of assigning new node to tail, you need to assign it to tail's next -
tail->next = (struct Node *) malloc(sizeof(struct Node) * 1);
in else block you have written this code
tail= malloc(sizeof(struct Node));
tail= tail->next;
tail->data=current->data;
tail->next = NULL;
Line 1: tail is pointing a node and all the member of this node is having value as tail has not been initialised.
Line2: tail->next which has garbage value is being assigned to tail. Now tail is not pointing any mallocked memeory. And you lost the pointer of the already mallocked memory
So actually linklist is not being made here

Resources