Inserting a node in a linked list - c

I had this exercice that asks me to create a function that adds a number in a new node to the head of a linked list based on a struct containing one integer. This is the struct:
struct Node
{
int data;
struct Node *next;
};
no problem till now. so I created one that takes 2 arguments: the integer to add and the pointer to the head of linked list, but it didn't work. this is my code:
void push(struct Node* head, int new_data)
{
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = head;
head = new_node;
}
So, what I did is that I made the new_node point to the same node pointed by head, after that I make the new node the new head of the linked list. it seems very logical, although it didn't work. on the other hand, when I give the function the adress of head pointer instead of the pointer itself, it does work:
void push(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
/* 2. put in the data */
new_node->data = new_data;
/* 3. Make next of new node as head */
new_node->next = (*head_ref);
/* 4. move the head to point to the new node */
(*head_ref) = new_node;
}
and this is the main for the function with double **:
int main()
{
struct Node* head = NULL;
push(&head,7);
push(&head,6);
push(&head,3);
return 0;
}
I understand that the second function should work, but I don't see why it is necessary to use the adress of head and not head itself. I would be glad if anybody could explain the reason to me, Thanks.

but I don't see why it is necessary to use the adress of head and not head itself.
In plain c code you can't have references (as in contrast to c++), but just pointers.
The value stored in the head pointer variable should be changed from within the call to push(), so you need to pass the address of the head variable to change the (single * pointer) value.
int main()
{
struct Node* head = NULL;
push(&head,7);
// ...
}
void push(struct Node** head_ref, int new_data)
{
// ...
/* 3. Make next of new node as head */
new_node->next = (*head_ref); // Dereferencing head_ref yields the current
// content of head
/* 4. move the head to point to the new node */
(*head_ref) = new_node; // Store the newly allocated memory address
// into the head pointer
}
As you were tagging your question c++ originally this isn't necessary using c++ code.
You can take the pointer parameter by reference as well:
void push(struct Node*& head_ref, int new_data)
// ^
{
// ...
/* 3. Make next of new node as head */
new_node->next = head_ref;
/* 4. move the head to point to the new node */
head_ref = new_node; // <<<<<<<<<<
}
int main() {
struct Node* head = nullptr;
push(head,7);
push(head,6);
push(head,3);
return 0;
}

Related

Linked list Pointer

I am learning C and I've come up with a conceptual question about pointers.
Here is a simple code to push (add to the beginning) an int to a linked list in C.
The following code works:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} node_t;
void push(node_t **head, int val) {
// head is a pointer to the pointer of the first node_t
node_t *new_node; // new pointer to a node
new_node = (node_t *)malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *head;
*head = new_node;
}
int main() {
// creating the first node
node_t *head;
head = (node_t *)malloc(sizeof(node_t));
head->val = 2;
head->next = NULL;
// pushing a value
push(&head, 1); // the '&' is important
return 0;
}
As you notice, we have to pass &head as a parameter. So I though changing the function so I could pass head instead. Here's the modified function :
void push(node_t *head, int val) {
node_t **p_head;
p_head = &head; // p_head is a pointer to the pointer of the first node_t
node_t *new_node; // pointer to a new node
new_node = (node_t *)malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *p_head;
*p_head = new_node;
}
Why does this version won't work ?
Thanks in advance.
You should be able to pass along the structure's pointer for the creation of another structure in a linked list. I would suggest looking at the linked list structure in a slightly different way.
Usually, in the creation of a linked list, whenever a new list item (aka structure in your case) is created, the "next node structure" pointer is set to null and the previous linked list member has its "next node structure" pointer updated to the pointer of the newly created structure. Making some revisions to your program I store some additional information in your structure and produce a linked list of ten members. Following is the revised code.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int val;
struct node *previous; /* Added this to use with the passed node pointer */
struct node *next;
} node_t;
node_t * push(node_t *nd, int val) /* Return the pointer of the newly created node */
{
node_t *new_node; // New pointer to a node
new_node = (node_t *)malloc(sizeof(node_t));
new_node->val = val;
new_node->previous = nd;
new_node->next = NULL;
return new_node;
}
int main()
{
node_t *work; // Pointer work variable for building a linked list of nodes
node_t *head;
head = (node_t *)malloc(sizeof(node_t));
head->val = 2; /* This value will get adjusted to provide unique values */
head->previous = NULL;
// Create a set of ten nodes.
work = head;
for (int i = 0; i < 10; i++)
{
work->next = push(work, (2 * i + i + 12));
work = work->next; /* Links this node to the newly created node. */
}
// Now travel down the chain and print out the pertinent statistics of the nodes.
work = head;
while (1)
{
printf("This node's values are: this->%p value->%d previous->%p next->%p.\n", work, work->val, work->previous, work->next);
if (work->next == NULL) /* We have reached the end of the list */
break;
work = work->next;
}
return 0;
}
When I ran this program, I received the following output on my terminal.
This node's values are: this->0x55bfd6edc2a0 value->2 previous->(nil) next->0x55bfd6edc2c0.
This node's values are: this->0x55bfd6edc2c0 value->12 previous->0x55bfd6edc2a0 next->0x55bfd6edc2e0.
This node's values are: this->0x55bfd6edc2e0 value->15 previous->0x55bfd6edc2c0 next->0x55bfd6edc300.
This node's values are: this->0x55bfd6edc300 value->18 previous->0x55bfd6edc2e0 next->0x55bfd6edc320.
This node's values are: this->0x55bfd6edc320 value->21 previous->0x55bfd6edc300 next->0x55bfd6edc340.
This node's values are: this->0x55bfd6edc340 value->24 previous->0x55bfd6edc320 next->0x55bfd6edc360.
This node's values are: this->0x55bfd6edc360 value->27 previous->0x55bfd6edc340 next->0x55bfd6edc380.
This node's values are: this->0x55bfd6edc380 value->30 previous->0x55bfd6edc360 next->0x55bfd6edc3a0.
This node's values are: this->0x55bfd6edc3a0 value->33 previous->0x55bfd6edc380 next->0x55bfd6edc3c0.
This node's values are: this->0x55bfd6edc3c0 value->36 previous->0x55bfd6edc3a0 next->0x55bfd6edc3e0.
This node's values are: this->0x55bfd6edc3e0 value->39 previous->0x55bfd6edc3c0 next->(nil).
Hopefully, this might give you some food for thought on pointer usage as it pertains to linked lists. Also, since the program is using "malloc" it usually is a good idea to have some cleanup in the program to make sure the memory is freed up (e.g. use the "free()" function).
Hope that helps.
Regards.

Node pointer to current Node during mutile function call

I have declared a global pointer ptr and want that it should point to current node during different function call.
This is a sample code where I am creating a new node in fun1 and inserting in link list. In func2 I want to update the other members of newNode in linklist with a different value.
Currently I am traversing the link list to get the current Node or last Node which I dont want since during insertion of new Records already we have to traverse to reach to last Node thus storing the address of last Node.
But by doing the below I am not getting the proper values. Kindly someone suggest where I went wrong.
I am doing like this :
#include<stdio.h>
#include <stdlib.h>
struct Node
{
int data1;
int data2;
struct Node* next;
};
struct Node* head=NULL;
struct Node* ptr =NULL; /* Global pointer */
void insertNode(struct Node ** , struct Node* );
void fun1();
void fun2();
void fun1()
{
struct Node* ptr1 =NULL;
ptr1 = (struct Node*)malloc(sizeof(struct Node*));
ptr1->data1=1; /* intilaizing with some values */
insertNode(&head,ptr1);
}
void fun2()
{
/* Updating the current Node in the linklist with new value . */
ptr->data2=2;
}
void insertNode(struct Node ** head, struct Node* NewRec)
{
if(*head ==NULL )
{
NewRec->next = *head;
*head = NewRec;
ptr=*head;
}
else
{
/* Locate the node before the point of insertion */
struct Node* current=NULL;
current = *head;
while (current->next!=NULL )
{
current = current->next;
}
NewRec->next = current->next;
current->next = NewRec;
ptr=current->next;
}
}
int main ()
{
fun1();
fun2();
while(head!=NULL)
{
printf("%d", head->data1);
printf("%d",head->data2);
head=head->next;
}
return 0;
}
You made a classic mistake.
This is wrong:
ptr1 = (struct Node*)malloc(sizeof(struct Node*));
The allocated space here is sizeof(struct Node*) which is the size of a pointer (usually 4 or 8 bytes depending on the platform). But you need to allocate space for the whole struct Node structure, whose size is sizeof(struct Node).
So you simply need this:
ptr1 = (struct Node*)malloc(sizeof(struct Node));
BTW: in C you don't cast the return value of malloc so you actually should write this:
ptr1 = malloc(sizeof(struct Node));

How can I free memory that has been dynamically allocated by one function from another function?

In the C program I've attached, I've defined a separate function called push() to add a node to the front of a linked list. push() allocates memory for a node on the heap, but I cannot free the memory here because then the work done by push() will not be reflected in the caller (main()). So how can I free the concerned heap-allocated memory from inside main()?
Any sort of help is appreciated. Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
/* Prototypes */
void push(struct node **headRef, int data);
int main(void)
{
struct node *head, *tail, *current;
int i;
head = NULL;
// Deal with the head node here, and set the tail pointer
push(&head, 1);
tail = head; // tail and head now point to the same thing
// Do all the other nodes using TAIL
for (i = 2; i < 6; i++)
{
push(&(tail->next), i); // add node at tail->next
tail = tail->next; // advance tail to point to last node
}
current = head;
while (current)
{
printf("%d ", current->data);
current = current->next;
}
printf("\n");
return 0;
}
/*
Takes a list and a data value.
Creates a new link with the given data and pushes
it onto the front of the list.
The list is not passed in by its head pointer.
Instead the list is passed in as a "reference" pointer
to the head pointer -- this allows us
to modify the caller's memory.
*/
void push(struct node **headRef, int data)
{
struct node *newNode = malloc(sizeof(struct node));
newNode->data = data;
newNode->next = *headRef; // The '*' to dereference back to the real head
*headRef = newNode; // ditto
}
You can free the allocated space in main like this -
struct node * tmp;
while(head){
tmp = head;
head = head->next; //this is to avoid loosing reference to next memory location
free(tmp);
}
Since you pass address of variable in push, therefore, this could be possible.

Passing a linked list head through a function as address in C

I have a question regarding passing the head of a linked list in C through a function. So the code goes something like this:
#include <stdio.h>
//Defining a structure of the node
struct node {
int data;
struct node* next;
};
void insert (struct node* rec, int x) {
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = NULL;
rec = temp; // head and rec is now pointing to the same node
}
void print(struct node* rec){
printf("%d", rec->data); //error occurs here
puts("");
}
main(){
struct node *head = NULL; //head is currently pointing to NULL
insert (head, 5); //Passing the head pointer and integer 5 to insert()
print(head);
}
So as you see, the error occurs when I tried printing rec->data. Why did the error occur? I thought since the pointer rec and head are all pointing to the same node in the heap, there should not be any problem?
Thank you.
You could pass a struct node** as suggested by #sje397.
However, I would suggest the following design (which, in my opinion is easier to reason about too):
/* returns the new head of the list */
struct node *insert (struct node* current_head, int x) {
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = current_head;
return temp;
}
and use it like
head = insert(head, 5);
In this case I would also rename the function something like push_front.
Just for completeness, I think #sje397 meant something like the following (Typical linked list code rewritten again and again by every C programmer...):
void insert(struct node **head, int x) {
struct node* new_head = (struct node*)malloc(sizeof(struct node));
new_head->data = x;
new_head->next = *head;
*head = new_head;
}
In C there is no pass by reference.
Your insert function isn't inserting a node in the list, its just changing the node which the head points to. Because of temp->next = NULL the list will always contain two nodes.
Another error is that you're just modifying a local copy of the head node.
To fix this You have 3 choices:
-You can make the head node global
-You can pass a pointer to the head node(pointer to pointer) to the function.
-You can return the modified head node by the function.
Redefine the insert function to:
void insert (struct node** rec, int x) {
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = NULL;
*rec = temp; // head and rec is now pointing to the same node
}

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!

Resources