I'm following the tutorial over here to build a linked list. I can't get the "Adding an item to the beginning of the list (pushing to the list)" part to work.
My code:
node_t* prepend(node_t **head, int val) {
//create new node pointer
node_t *new_node = (node_t*) malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *head; //set its next to existing head (pointer of pointer)
//update existing head to point to new node
*head = new_node;
return *head;
}
int my_first_ll() {
//define a local variable called head that will point to the first node
node_t *head = NULL;
head = (node_t*) malloc(sizeof(node_t));
//check for null pointer
if (head == NULL) {
return 1;
}
//note how because head is a pointer we're using -> rather than dot notation to access attributes
head->val = 1;
head->next = (node_t*) malloc(sizeof(node_t));
head->next->val = 2;
head->next->next = NULL; //last item should point to a NULL
head = prepend(head, 0);
print_list(head);
}
It prints:
Currently at node 0
Instead of
Currently at node 0
Currently at node 1
Currently at node 2
So it seems when I insert the new head I fail to link to the previous one - but I just can't figure out how.
I found a solution: instead of passing **head to prepend like they do in the tutorial, passing *head solves it. Thus the final code:
node_t* prepend(node_t *head, int val) {
//create new node pointer
node_t *new_node = (node_t*) malloc(sizeof(node_t));
new_node->val = val;
new_node->next = head; //set its next to existing head (pointer of pointer)
//update existing head to point to new node
head = new_node;
return head;
}
Could someone explain why one works and the other doesn't? And why did they use two stars in the tutorial? And if two stars is actually correct, then why is it failing for me?
You can pass **head to the function, so you basically pass a pointer to a pointer:
void prepend(node_t **head, int data){
node_t *new = malloc(sizeof(node_t));
//set data
new->data = data;
//set the next pointer of new to current head
new->next = *head;
//now set the newly created node to be the new head
*head = new;
}
But the you'd have to call the function like this:
int main()
{
node_t *head = NULL;
prepend(&head, 3);
prepend(&head, 6);
printlist(head);
deltelist(&head);
return 0;
}
And theres no reason to return the *head in your function because you basically change the head node you created in main.
So if I now print my list, it prints
6
3
And never forget to delete the list after you used it.
Hope this helped you :)
Related
I am learning how to reverse a linked list recursively. I am confused with the last 4 lines.
node *reverse_linked_list_rec(node *head){
if (head->next==NULL){
return head;
}
node *smallans= reverse_linked_list_rec(head->next);
node *tail = head->next;
tail->next = head;
head->next = NULL;
return smallans;
}
Let's say I am reversing
1 2 3 NULL
by recursion, it reaches at 3 NULL and then by base case returns
2 3 NULL
here head=2, smallans=2 (not sure).
Why we are returning smallAns here and how it is changing?
smallans is a confusing variable name because it's actually the old tail being passed back through the list to become the new head which is ultimately returned to the caller.
Its next pointer changes when these lines execute in the parent function call:
// when head->next->next == NULL ...
node *tail = head->next; // ... `tail` points to the old tail (new head) ...
tail->next = head; // ... and this sets the new tail's next pointer to
// the old second-to-last node (new second node).
tail is a misleading name here--I associate a "tail" with a single node that terminates the entire list, not a previous node. new_prev or old_next seem more appropriate here depending on whether you want to name things relative to the node roles in the new list or the original list.
As a minor point, I recommend using if (!head || !head->next) to avoid a potential null pointer dereference.
I'd write the function as follows:
node *reverse_linked_list_rec(node *head) {
if (!head || !head->next) {
return head;
}
node *old_tail = reverse_linked_list_rec(head->next);
node *old_next = head->next;
old_next->next = head;
head->next = NULL;
return old_tail;
}
Aside from intellectual curiosity, recursion is a poor choice for linked list operations since it adds function call overhead, you can blow the stack and the logic isn't any easier to follow than iterative, in most cases.
Case in point, here's a complete example with an iterative version:
#include <stdio.h>
#include <stdlib.h>
struct node {
int id;
struct node *next;
};
struct node *make_node(int id) {
struct node *n = malloc(sizeof(*n));
if (!n) exit(1);
n->id = id;
n->next = NULL;
return n;
}
struct node *reverse_linked_list(struct node *head) {
struct node *prev = NULL;
for (struct node *curr = head; curr;) {
struct node *old_next = curr->next;
curr->next = prev;
prev = curr;
curr = old_next;
}
return prev;
}
void print_linked_list(struct node *head) {
for (; head; head = head->next) {
printf("%d->", head->id);
}
puts("");
}
void free_linked_list(struct node *head) {
while (head) {
struct node *tmp = head;
head = head->next;
free(tmp);
}
}
int main() {
struct node *head = make_node(1);
head->next = make_node(2);
head->next->next = make_node(3);
print_linked_list(head); // => 1->2->3->
head = reverse_linked_list(head);
print_linked_list(head); // => 3->2->1->
free_linked_list(head);
return 0;
}
As another minor point, since the linked list is being mutated I'd probably go for a header like void reverse_linked_list(struct node **head);. Otherwise, it seems too easy to call the non-void function, ignore the return value and wind up with a memory leak or crash when head in the caller scope (which has become a tail pointing to null) is dereferenced.
typedef struct node { int data; struct node *next; } NODE;
NODE* add_head(NODE **phead, int data) {
NODE *new = (NODE *)malloc(sizeof(NODE));
new->data = data;
new->next = *phead;
*phead = new;
return new;
}
NODE* add_tail(NODE **phead, int data) {
NODE *p, *new = (NODE *)malloc(sizeof(NODE));
new->data = data;
new->next = 0;
if (*phead == 0) *phead = new;
else
{
for (p = *phead; p->next; p = p->next);
p->next = new;
}
return new;
}
We have a singly linked list as shown above in the functions. The node consists of the data type int and the pointer to the next node in the list. We have two functions defined. The first one changes the head node, or adds the new head node before the previous head node. The second function adds the tail node (the last one in the list). In the main, we call them like:
NODE *head = 0;
NODE *c1 = add_head(&head, 1);
NODE *c2 = add_tail(&head, 3);
Now, look at this function:
NODE* add_after(NODE *node, int data) {
NODE *new = (NODE *)malloc(sizeof(NODE));
new->data = data;
new->next = node->next;
node->next = new;
return new;
}
That function adds a node after the argument node. And, in main, if we want to add a node after c1 previously defined, we call the function like:
*c3 = add_after(c1, 4);
My question is: What is the difference between first two and the third function in terms of the arguments. In first two functions, we have an argument **phead and in the third function, *node. Do we really need **phead, why can't we just put *phead and in the main call it like:
NODE *c1 = add_head(head, 1);
I hope you understood what I meant, I find it difficult to explain.
The address of the first element (of type NODE) is contained in a pointer (of type NODE *)
the add_head() functions modifies this pointer. As you are programming in C, blatantly lacking parameter-passing-by-reference, your only option is to transmit its address.
So, the parameter is of type NODE** (adress of a pointer to a NODE).
for add_after() the parameter gives the address of the NODE to be modified. You don't have to modify that address.
I don't understand why we have to return pointers to the head node after a node has been added to a linked list.
struct node *append(int v) {
struct node *ptr;
struct node *t;
ptr=head;
while (ptr->next != tail) ptr = ptr->next;
t=(struct node *) malloc(sizeof *t);
t->value=v;
t->next = tail;
ptr->next = t;
return ptr; // why return ptr?
}
It depends of the context of your problem. Usually in linked list problems you have to return the head of the list so you can have your data structure consistent, but I infer from your code that the head is a global variable.
Unless the code that are invoking this function needs to know the location of the new node created, you don't need to return the node since your head is a global variable (again, if my assumption is correct).
Besides this, I suggest to revise your function since I see some cases you are missing here (what if the list comes empty and you have to change the head for example?)
First of all the function is invalid. When the list is empty and the first element is added head can be equal to NULL. So using expression head->next that in the function code corresponds to ptr->next results in memory access violation.
Also in my opinion it is not a good idea to name NULL as tail. I would explicitly use NULL. Otherwise the code can confuse readers.
Neverteless the function can look the following way
struct node * append( int v )
{
struct node *t = ( struct node * )malloc( sizeof( *t ) );
t->value = v;
t->next = tail;
if ( head == tail )
{
head = t;
}
else
{
struct node *current = head;
while ( current->next != tail ) current = current->next;
current->next = t;
}
return t;
}
As for your question then I also do not understand why the function returns ptr instead of t. It should return t. In this case the function would be more correct and efficient because it would return head when the first element is appended to the empty list and when a next non-first value is appended to the list and the head would be some node (not necessary the head itself) the while loop had no iteration because the first expression ptr->next would be equal already to NULL.
The function should return the last appended node as in the implementation I have shown.
I am sure that it is simply an error in the design of the function.:)
This drawback will be more visible if do not use the global variable head within the function but declare it as a function parameter. For example
struct node * append( struct node *head, int v )
{
struct node *t = ( struct node * )malloc( sizeof( *t ) );
t->value = v;
t->next = tail;
if ( head == tail )
{
head = t;
}
else
{
struct node *current = head;
while ( current->next != tail ) current = current->next;
current->next = t;
}
return t;
}
In this case the function call in main could look for example the following way
struct node *head = NULL;
struct node *current;
int i;
head = append( head, 0 );
for ( i = 1, current = head; i < 10; i++ ) current = append( current, i );
In this case the call of append would be very efficient because within the function the while loop would not make even one iteration.
Linked lists are often implemented with a NULL head when the list is empty. In this case, you have to return the head of the list when the head is a local variable, or when it is a global and you want to have more than one list using the same function. When adding a node, the head may have changed, even if adding at tail, in the case the list was empty there is a new head.
But another way to do is to always have a node at the head, just here to indicate the head, and adding/reading/deleting nodes after this head in order to treat datas in the list. In this case, returning the head is useless, because the head never change.
You can detect the tail of the list when for a node n: n->next == NULL, using a head equal to NULL when the list is empty, as the following code do:
// add at the tail of the list:
struct node * add_to_list_tail(struct node * head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
t->next = NULL; // next is set to NULL because it is the new tail
if(head == NULL) {
// in the case the list is empty
head = t; // t become the new head, because the list was empty
} else {
// in the case the list isn't empty
struct node * n = head;
// the following loop will stop when n->next == NULL, and n will point to the tail
while(n->next != NULL) {
n = n->next;
}
n->next = t;
}
return head;
}
// add at the head of the list:
struct node * add_to_list(struct node * head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
t->next = head; // make t become the new head
return t; // return t because it is the new head
}
int main() {
struct node * head = NULL;
head = add_to_list(head,1);
head = add_to_list(head,2);
head = add_to_list_tail(head,3);
}
If you don't want to return the head, you can also pass a pointer to the head pointer, as parameter for the functions that manipulate the list. A short sample code:
void add_to_list(struct node ** head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
// make t become the new head:
t->next = *head;
*head = t;
}
int main() {
struct node * head = NULL;
// we pass &head, the adress of variable head, as parameter:
add_to_list(&head,1);
add_to_list(&head,2);
struct node * n = head;
while(n != NULL) {
printf("\nvalue: %d",n->value);
n = n->next;
}
}
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!
I've implemented a Linked-List with a Pop function in C:
Node * pop (Node * head) {
Node * temp = head;
printf("Temp is: %s\n", temp->val);
if (head->next != NULL) {
*head = *head->next;
}
printf("Temp is: %s\n", temp->val);
return temp;
}
And the output when I pop would be something like:
Temp is: node1 value
Temp is: node2 value
That is to say that temp is becoming temp->next when I assign *head = *head->next.
So how can I get the value of the current head and return it while also moving the head of the Linked-list to head->next?
Doing head = head->next does NOT remove the reference to the first node. (i.e. When I print the list, the first node is still there).
First, note that your code (and some of the previous solutions) will never pop the last element off the list. You want
if (*head != NULL) ...
Next, passing a pointer to a pointer will work. But it's actually better to make a list header like this:
typedef struct node_s {
struct node_s *next;
... data declaration here
} Node;
typedef struct list_s {
struct node_s *head;
} List;
void init_list(List *list) {
list->head = NULL;
}
Now declare a list like this:
List list[1];
init_list(list);
Declaring an array of one element makes every reference to list a pointer automatically, which eliminates lots of &'s in your code. Then it's nice and clean to implement push and pop:
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
}
return head;
}
Why is this better? Say you decide later to keep a count of items in the list. With the separate header node this is very easy:
typedef struct list_s {
struct node_s *head;
int length;
} List;
void init_list(List *list) {
list->head = NULL;
length = 0;
}
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
++list->length;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
--list->length;
}
return head;
}
Note no calling code needs to change. With the pointer to pointer approach you are at a dead end. There are many other use cases where having a separate list header makes your code more flexible for future changes.
Your need to pass the address of head for your function to modify it. Then your function needs to dereference this address. Further, the last pop() needs to change *AddressOfHead as well
Node *pop(Node **AddressOfHead) {
Node *temp = *AddressOfHead;
if (temp) {
*AddressOfHead = temp->next;
}
return temp;
}
...
// Usage example
Node *TopOfList = pop(&Head);
Others have told you how to fix it, let me answer why temp changed..
Node * pop (Node * head) {
You are passing head as a pointer to a Node.
Thus when you do
*head = *head->next;
I think it is parsed as
*head = *(head->next);
And thus COPIES the object that is in next into the object at head, which is ofcourse the same object at temp.
Pointers are passed by value. That is, when you pass a pointer to the stack, a change in the called function to what the pointer points to is not reflected in the calling function.
In order for the value of the node pointer to be changed in the calling function, you need to pass the stack as a pointer to a pointer:
Node* pop (Node** head) {
Node* temp = *head;
if (temp) {
*head = temp->next; // to update stack in calling function
temp->next = NULL; // to detach temp from the rest of the list
}
return temp;
}
You do not need to check if ((*head)->next) or in this case if (temp->next) before updating the value of *head, because if you are at the last node of the stack and the next node is NULL, you want the list to be NULL anyway.
Karthik T's answer has the right explanation for why the value of temp was changing in your original code.
void pop(struct node** tol) {
struct node* t = *tol;
while (t->link->link != NULL){
t = t->link;
}
t->link = NULL;
}