trying to understand this linkedlist insertion code - c

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

Related

Problem deleting head node in a doubly linked list in C

I'm trying to implement a doubly linked list in C. While coding it up, I ran into an issue when trying to delete the first element of the list.
Here is is a toy example that illustrates the problem:
#include<stdio.h>
#include <stdlib.h>
typedef struct Node{
struct Node * next;
struct Node * previous;
int data;
}Node;
Node* create_dll(int array[], int arrSize){
Node *current = (Node*)malloc(sizeof(Node));
current->next = NULL;
current->data = array[0];
for(int i = 1; i < arrSize; i++){
Node *temp = (Node*)malloc(sizeof(Node));
temp->data = array[i];
temp->next = current;
current->previous = temp;
current = temp;
}
current->previous = NULL;
return current;
}
void print_dll(Node *head){
if(head != NULL){
Node *current = head;
while(current!=NULL){
printf("%d \t", current ->data);
current = current->next;
}
}
puts(" ");
}
void delete_head(Node *head){
Node *current = head;
head = head->next;
//head ->previous = NULL;
free(current);
}
void kill(Node *head){
Node *current = head;
while (current != NULL){
Node *previous = current;
current = current ->next;
free(previous);
}
}
int main(){
int array [] = {1, 2, 3, 4, 5};
int arrSize = 5;
Node *head;
head = create_dll(array, 5);
print_dll(head);
delete_head(head);
print_dll(head);
kill(head);
return 0;
}
Whenever I try to run the code in main, which creates a DLL, then prints what's in it, then attempts to delete the first node, then print the list again, I get the following result:
5 4 3 2 1
5
Now, I know that one fix would be to make head a global variable, but that will be problematic in other sections of the code, plus I don't really want to go that route. I also don't want to modify any of the function headers, or anything in the main.
I did get this to work by implementing the DLL with a dummy node that head always points to, but I"m sure there is a simple fix to this implementation that avoids all this.
Basically, if I can change what head points to in the delete_head function
and have this change be reflected in the main function, that would be a solution. Otherwise, I would be happy just to understand why this code fails to do what I want.
Any help is very much appreciated! Thanks!
The problem is that when you call delete_head, C parameter passing is by value, so head isn't changed on return. You need to implement it like this:
void delete_head(Node **head){
Node *current = *head;
*head = current->next;
//head ->previous = NULL;
free(current);
}
And call it like this: delete_head(&head);
The trick is, all the external pointers are pointing to individual nodes. So when you cut the head off from the rest of the list, all the pointers to head keep pointing to it—you get the single node on its own, not the rest of the list.
I would solve this by adding an additional struct.
typedef struct DLL{
struct Node * head;
} DLL;
When you want to create the list, create a DLL pointing to the head, instead of returning the head itself. Now when you want to change the head, change the pointer inside the DLL struct. All the references to the DLL itself can stay the same, but now the head inside it has changed, and all those references will see the new head when they look for it!

C Linked List copy segfault

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.

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!

Adding element to front of linked list in C

I'm following the Stanford CS Ed Library tutorial on Linked Lists. I am trying to add a new list to the front of my linked list, and it's not working based on the printout I get from the Length function defined below.
#include <stdio.h>
#include <stdlib.h>
//build new struct for node
//node has value and points to next node
struct node{
int value;
struct node *next;
};
//declare a new struct node that contains 3 nodes (head, middle, tail)
struct node *Build123(){
struct node *head, *middle, *tail = NULL;
head = malloc(sizeof(struct node));
middle = malloc(sizeof(struct node));
tail = malloc(sizeof(struct node));
head->value = 3;
head->next = middle;
middle->value = 5;
middle->next = tail;
tail->value = 9;
tail->next = NULL;
return head;
};
//declare a function Length and variable counter to calculate size of list
int Length(struct node *head) {
int count = 0;
struct node *iterator = head;
while (iterator != NULL) {
count++;
iterator = iterator->next;
}
return count;
}
//declare function Push to add new lists that would be added to the front
void Push (struct node **headRef, int value){
struct node *newNode;
newNode = malloc(sizeof(struct node));
newNode->value = value;
newNode->next = *headRef;
}
int main(){
//instantiate the 3 element linked list named beast
struct node *beast = Build123();
//add 2 elements to the front of the linked list via pass by reference
Push(&beast, 6);
Push(&beast, 12);
//calculate length of linked list after elements have been added
int len = Length(beast);
//print length of linked list to screen
printf("%d\n",len);
return 0;
}
I get 3, when I expect to receive 5. Would you please assist me to find the error in the code that prevents me from obtaining the value I expect? I could not figure out why despite much tinkering. Thank you!
The problem is that when you do something like Push(&beast, 6); what beast points to is unchanged by the function Push. Even though Push adds more elements to the linked list, when you call Length on beast later it calls it on the same node that beast originally had at the start - so it is completely unknowing of the extra, added nodes.
At the end of Push(), you need to do this:
*headRef = newNode;
so that beast will correctly point to the new start of the list.
You don't modify headRef in your Push function, so your list's head never actually changes. beast always stays pointing to the original node it was created to point to. Add this line:
*headRef = newNode;
In Push(), and you'll be set.
At the end of the push() method, you have to add:
*headRef = newNode
This is because headRef should always point to the first node in your linked list.

Adding a node into a linked list, right after the head

I have a linked list, and I need to create a node right after the head..
it means I have something like this:
node *head = NULL;
and my linked list in the end should be like :
head -> node -> NULL...
but when I use a normal addNode function, it gives me a runtime error(not sure which, my debug has problems)...
this is what I wrote:
void addNode(node *head)
{
node *temp = head; // a temp to not move the head
node *newNode = (node*)malloc(sizeof(node)); // The new node
while (temp -> next != NULL)
{
temp = temp -> next // Getting to the last node
}
temp -> next= newNode; // Adding the new node into the linked list insted of the NULL
newNode -> next = NULL; // Adding the NULL after the new node
}
This code works great to me when I have a linked list with already 1 or more nodes ,but if the linked list only has a head, it does problems to me... how can I solve the problem?
(if you didnt understand my problem - With the addNode function I wrote here, i'm getting a runtime error for adding a new node into a head that points to NULL already)..
Thanks, Amit :)
Need to check if head is NULL on entry, otherwise a null pointer will be dereferenced:
node *temp = head; /* temp set to head, possibly null. */
while (temp->next != NULL) /* 'temp' dereferenced, undefined behaviour
if 'temp' is null. */
In order for the change to be seen by the caller, you will need to pass in a node** (as suggested by wildplasser), as C passes arguments by value. Change to (for example):
void addNode(node **head)
{
node *newNode = malloc(sizeof(node)); /* No need to cast. */
if (newNode)
{
newNode->next = NULL;
if (NULL == *head)
{
*head = newNode; /* Set the head, as there isn't one yet. */
}
else
{
node* temp = *head;
while (temp->next) temp = temp->next;
temp->next = newNode;
}
}
}
This would be called:
node* my_list = NULL;
addNode(&my_list);
You have to check if Head is null. Otherwise when you try to check
head->next != NULL
head is NULL so you are referring to random place in memory
You can't add node after head if head is NULL. You have to allocate memory for head and then set 'next' pointer. By the way why u want to set head->next while head is null?
EDIT
Mayby you should try add flag to nodes like bool active and set it false when you want to pass it.
I'll try to say it in another way. You can't set head->next because head is NULL. NULL means, that it's just a pointer, to nowhere. It's a variable where u can place some address, but nothing else. If u want to have there a structure, like node, you have to place there address of new object of type Node:
Node element = malloc(sizeof(Node));
head = element;
After that u will have in head address of Node object and u will be able to revoke to variables (like Node *next) inside this structure.
You could use a pointer to pointer:
void addNode(node **pp)
{
node *newNode = malloc(sizeof *newNode); // The new node
if (newNode) {
newNode->next = *pp; // steal the parent. (this will also work if *pp happens to be NULL)
*pp = newNode; // let *pp point to the new node
}
}
To be called like:
...
node *head = NULL;
addNode( &head);
...

Resources