linked list basic architecture in C - c

I am new to C and I want to implement the linked list. This is my initial copied code:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data; // integer data
struct Node* next; // pointer to the next node
} Node;
int main() {
Node* A = NULL;
Node* temp = malloc(sizeof * temp);
temp->data = 2;
temp->next = NULL;
A = temp;
printf("%d", A);
return 0;
}
I have understood how pointers work, for example:
//Example 2
int a = 2;
int* p = &a;
such that p holds the address of a and *p holds the content of it.
In the node example, the basic idea is to create an initial node, and then from there, to link other nodes when inserting at the end for instance. So, when we did this:
Node* A = NULL;
Node* temp = malloc(sizeof * temp);
we create a node A, my first question here, why I can't use the same concept of accessing its address and content NULL the same as in Example 2 or how can I do that?
Second, when we created node temp and assigned 2 to its data, and NULL to its next, it's all clear, but when we did A = temp, this is not clear, what did we assigned exactly? I mean, how can I get from A to the next node, A now has A->data = 2 and A->next = NULL, I was expecting A->next to store the address of temp, no? Please if you can explain in the simplest terms the basic abstract inner workings?
Update
For example, if I want to create a linked list with two elements 2 and 3. Is the following code correct?
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data; // integer data
struct Node* next; // pointer to the next node
} Node;
int main() {
Node* A = NULL;
Node* temp = malloc(sizeof * temp);
temp->data = 2;
temp->next = NULL;
A->next = temp;
Node* temp1 = malloc(sizeof * temp1);
temp1->data = 3;
temp1->next = NULL;
temp->next = temp1;
return 0;
}

when we did A = temp, this is not clear, what did we assigned exactly?
temp contains the the address of the node allocated by malloc.
You assigned this to A. (A = temp;)
So A contains the the address of the node allocated by malloc.
Now can I get from A to the next node
What next node? You only ever created one node.
I was expecting A->next to store the address of temp, no?
At no point do you get the address of temp. And there's no point in doing that. So I think you mean the address of the node (the address in temp). But why wou ld that be in A->next? You never assign temp to A->next. You assign NULL to A->next (temp->next = NULL;).
Please if you can explain in the simplest terms the basic abstract inner workings?
temp holds the address of the node you allocated.
You assign this to A, so it holds the same address.
*temp and *A is the node you allocated.
(*temp).data aka temp->data is its data field (currently containing 2).
Since A has the same value as temp, (*A).data aka A->data can also be used to access its data field.
(*temp).next aka temp->next is the address of the next node (currently NULL).
Since A has the same value as temp, (*A).next aka A->next can also be used to access its next field.
Node *temp Node anon
# 0x1000 # 0x2000
+------------+ +------------+
| 0x2000 ---------+---->| data: 2 |
+------------+ | | next: NULL |
| +------------+
Node *A |
# 0x1004 |
+------------+ |
| 0x2000 ---------+
+------------+
(The addresses are completely made up, of course.)
Is the following code correct?
No. You have:
Node* A = NULL;
...
A->next = temp;
A is NULL. It doesn't point to a node. So attempting to set the next field of the node to which A points makes no sense. This is undefined behaviour.

Related

Append a node in a linkedlist - why segmentation error?

I am implementing a linked-list in C with structure
struct node
{
int data;
struct node *next;
};
I have written the append function to add a node at the end of a linked-list, as below, and display function to display all the nodes. But display is giving segmentation fault due to some inconsistency in the append function I think. What can be wrong here? My book does have a similar function for append, using malloc. I want to know what is wrong in my function.
void append(struct node **q, int d)
{
struct node *temp;
temp = *q;
printf("\nBegin: Address at temp = %u", temp);
while (temp!= NULL){
temp = temp->next;
printf("\nTravel: Address at temp = %u", temp);
}
struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;
printf("\nEnd: Address at *q = %u\n", *q);
printf("\n*q->data = %d next = %u", (*q)->data,(*q)->next );
}
void display(struct node *q)
{
printf("\n");
while (q != NULL){
printf(" -> %d",q->data);
q = q->next;
}
}
int main(int argc, char *argv[])
{
struct node *p;
p = NULL; /* empty linked list */
printf("\nNo. of elements in the Linked List = %d", count(p));
append(&p,1);
display(p);
append(&p,2);
display(p);
printf("\nNo. of elements in the Linked List = %d", count(p));
}
Output:
No. of elements in the Linked List = 0
Begin: Address at temp = 0
End: Address at *q = 6684096
*q->data = 1 next = 0
-> 1Segmentation fault
However, when I replace
struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;
with
temp = *q;
*q = malloc(sizeof(struct node))
temp->data = d;
temp->next = NULL;
the error is gone.
Can someone explain the reason?
Here you use an address of a local variable in a way which makes it accessable after you left the function:
*q=&p1;
Then you leave the function.
Whenever that is accessed later, it will access memory which is NOT the local variable anymore.
You need to allocate the memory for the variable. Use malloc() for that.
E.g.:
struct node *p1;
p1 = malloc(sizeof(*p1));
/* skipping recommended check of success/NULL */
p1->data = d;
p1->next = NULL;
*q=p1;
There are more problems, like you let the list start with the new node, which is followed by NULL, which loses/leaks all of your previous list. But the immediate problem is caused by referencing the memory location of a bygone local variable after it exists.
regarding the loop:
while (temp!= NULL){
This results in temp containing NULL so this has stepped all the way through the linked list and off the end of the list.
Suggest:
while (temp->next != NULL){
as this will stop stepping through the linked list when it is pointing to the last 'node' in the linked list.
Then need to use temp as the pointer to the last 'node' in the linked list (where you want to append a new node)
regarding:
struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;
this creates the new 'node' on the stack. However, anything on the stack 'disappears' when the function returns.
q is a pointer to the first 'node' in the linked list, not the last 'node' in the linked list. Suggest using temp as (after correcting 1) points to the last 'node' in the linked list
each 'node' needs to be created in the 'heap' memory, via malloc() or calloc() so it still exists after the function exits.
regarding:
temp = *q;
*q = malloc(sizeof(struct node))
temp->data = d;
temp->next = NULL;
the error is gone.
NO, the error is NOT gone. Rather, this always inserts the new 'node' as the second 'node' in the linked list. (and breaks the link to the following nodes of the linked list.)
the posted code fails to return all the allocated memory to the heap (via calls to free() ) The result is a memory leak for each and every call to malloc().

Linked list- getting segmentation fault

void AlternatingSplit(struct Node* source, struct Node** aRef,
struct Node** bRef)
{
/* split the nodes of source to these 'a' and 'b' lists */
struct Node* a ;
struct Node* b;
struct Node* current = source;
if(current){
a=current;
b=current->next;
current=b->next;
a->next=NULL;
b->next=NULL;
}
while(current) {
a->next=current;
b->next=current->next;
if(b)
current=b->next;
b=b->next;
a=a->next;
}
*aRef = a;
*bRef = b;
}
I am getting segmentaton fault here i dont know why pls help.
This question is to alternating split linkedlist nodes. I m using two pointers a and b and adding to it alternatingly but its giving error . pls help me
Like most linked-list rearrangement exercises, pointers to pointers make the job much, much easier. The point of this exercise it to flex your ability to change the next pointers without ever changing the data values of said-same. Pointers to pointers are an excellent way to do that in C.
This is especially trivial because you were already provided the target pointer-to-pointer arguments that we can reuse for building each list. How that works is best understood by demonstrating a technique for building a forward-chained linked list using a single head pointer and a pointer to pointer p:
struct Node *head, **pp = &head;
for (int i = 1; i <= 20; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->data = i;
pp = &(*pp)->next;
}
*pp = NULL;
Yes, it needs error checking, but the algorithm is what to focus on here. This code uses only pp to build the actual list. The rule is this: pp is a pointer to pointer to Node, and always holds the address of the next pointer to Node to populate. That's what pointers to pointers do: hold addresses of pointers. In this case pp initially holds the address of the head pointer. With each new node added pp takes the address of the next pointer of the previously just-added node. Makes sense, right? That will be the next pointer where we want to hang the next node. This process continues until we finish the loop. At that pointer pp holds the address of the last node's next pointer, which we set to NULL to terminate the list.
Now, knowing what we learned above, consider this:
void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
while (source)
{
*a = source;
a = &(*a)->next;
source = source->next;
if (source)
{
*b = source;
b = &(*b)->next;
source = source->next;
}
}
*a = *b = NULL;
}
Example
A short example using both the forward-chaining build algorithm I showed first, and the split algorithm I showed after, appears below. Some utility functions for printing the list are included. I leave freeing the lists (there are two now, remember to walk both and free each node) as an exercise for you:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
while (source)
{
*a = source;
a = &(*a)->next;
if ((source = source->next))
{
*b = source;
b = &(*b)->next;
source = source->next;
}
}
*a = *b = NULL;
}
void PrintList(struct Node const *p)
{
while (p)
{
printf("%d ", p->data);
p = p->next;
}
fputc('\n', stdout);
}
int main(void)
{
struct Node *head, **pp = &head;
for (int i = 1; i <= 20; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->data = i;
pp = &(*pp)->next;
}
*pp = NULL;
PrintList(head);
struct Node *a = NULL, *b = NULL;
AlternatingSplit(head, &a, &b);
PrintList(a);
PrintList(b);
return EXIT_SUCCESS;
}
Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 3 5 7 9 11 13 15 17 19
2 4 6 8 10 12 14 16 18 20
There are few errors in your code -
Trying to access node->next , without checking whether node exists or not .
Not tackling the corner cases depending on the length of linked list (i.e. if length (linked list) < 3 )
And then comes the blunder , you are trying to make the new linked lists and then in the end aRef and bRef is assigned to the last node in their respective linked lists.
Try to deal with these problems and for reference you can see the code below.
void AlternatingSplit(struct Node* source, struct Node** aRef,
struct Node** bRef)
{
struct Node* a,b;
struct Node* current = source;
if(current){
a=current;
b=current->next;
// moving 'current' one step at a time will secure the code from crashing for corner cases
current = current->next;
if(b)
current=b->next;
a->next=NULL;
b->next=NULL;
//link aRef bRef right here
*aRef = a;
*bRef = b;
}
else {
*aRef = source; // Null
*bRef = source; // Null
return;
}
while(current)
{
a->next=current;
a=a->next;
b->next=current->next;
b=b->next;
current=current->next;
if(b){
current = b->next;
}
}
b->next = NULL;
a->next = NULL;
}
Hope this will help .
Keep asking , keep growing :)

C: passing address of pointer vs passing address of array

This was an remote coding test I got a few days ago, and I've already submitted the answers so I'm not cheating here.
The question is fairly simple: implement a function to delete an item from a linked list. But with one catch: the linked list is in the form of an array.
typedef struct _Node{
int val;
struct _Node* next;
} Node;
Test input provided by the interviewer, which we can modify slightly
void printLL(Node* root){
Node* current = root;
while (current){
printf("%d\n", current->val);
current = current->next;
}
}
int main(){
Node list[6];
list[0].value =1; list[0].next = list+1;
list[1].value =2; list[1].next = list+2;
list[2].value =3; list[2].next = list+3;
list[3].value =4; list[3].next = list+4;
list[4].value =5; list[4].next = list+5;
list[5].value =6; list[5].next = 0;
delete(&list, 3) // this gives segmentation error with my implementation;
printLL(list);
return 0;
}
My answer, which is standard for linked list deletion:
void delete(Node** root, int val){
Node* current = *root;
Node* prev = NULL;
if ((*root)->val == val){
*root = (*root)->next;
//free(current); // test case not dynamically allocated
return;
}
while (current && (current->val != val)){
prev = current;
current = current->next;
}
if (!current){
printf("value not found\n");
return ;
}
else{
prev->next = current->next;
//free(current);
}
}
However, if I use pointers instead, then the function works
Node* p = list;
delete(&p, 3);
I think I understand the difference between &list and &p as function argument:
**Variable name | Variable value | Variable address**
list | address of first elem | address of first elem
p | address of first elem | some random address of the pointer
But since in the delete function we are operating with *list and *p respectively, their value should also be the same.
My guess now is because of in
*root = (*root)->next;
if *root is an array name, then it's illegal as we cannot reassign it. But if *root is a pointer, then we are freely to reassign them. Am I correct on this?
Thank you for reading through this long and messy post.

Why is this linked list printing the last element indefinitely?

I was completing a Hackerrank challenge involving addition of elements to a linked list and printing it.
The input is of this format: A set of integers, in which the first element gives the size and the rest are the components of the list.
I completed the challenge in Java, but I am not able to do it in C.
Input of 4 2 3 4 1 should print 2 3 4 1, but this snippet that I coded is giving me 1 1 1 1 1 1 .... {truncated}
My approach: Declare a new struct temp of type Node (with the data input as data field, and NULL in next field), then iterate thorough the linked list with head as the starting point, and when it reaches the last element, change the next field of the last element to the address of the current element.
Code:
#include <stdlib.h>
#include <stdio.h>
typedef struct Node{
int data;
struct Node* next;
}Node;
Node* insert(Node *head,int data)
{
Node temp = {data, NULL} ;
if (head == NULL)
{ head =&temp;
return head;
}
else{
Node* current = head ;
while(current->next !=NULL)
current = current->next ;
current->next = &temp;
return head;
}
}
void display(Node *head)
{
Node *start=head;
while(start)
{
printf("%d ",start->data);
start=start->next;
}
}
int main()
{
int T,data;
scanf("%d",&T);
Node *head=NULL;
while(T-->0){
scanf("%d",&data);
head=insert(head,data);
}
display(head);
}
List nodes must be allocated dynamically. This
Node temp = {data, NULL} ;
declares a local variable. Referring to its address outside the scope of its declaring function is undefined behavior.
Replace with
Node *temp = malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
Now thtat temp is a pointer, expression &temp has to be replaced with temp as well.
Because you save a pointer to a local variable in the list. When the insert function returns, the local variable temp will go out of scope and cease to exist. Saving a pointer to it and using that pointer will lead to undefined behavior. Find a good beginners book and read about dynamic allocation of memory.

how to free memory for doubly linked list program in c

Past few days I'm working on my c\c++ skills. I was going through my Data structure book and then I thought why not implement doubly linked list program. I wrote the program; surprisingly it work fine too, but , I'm not sure whether I've written it correctly. I'm not able to figure it out how to free the memory I've allocated. Please help me with this guys.
Also if any of you can explain me this "while(linkNode!=0)", i'll be really thankfull.
#include<stdio.h>
#include<malloc.h>
struct node
{
int x;
struct node * next;
struct node * prev;
};
struct head
{
unsigned int count;
struct node * hd;
struct node * tl;
};
void main()
{
int i =0;
struct node * linkNode;
struct head *hdd;
hdd = (head *)malloc(sizeof(head));
linkNode = (node *) malloc(sizeof(node));
hdd->count = 1;
hdd->hd = linkNode;
linkNode->prev = 0;
linkNode->next = 0;
linkNode->x = 0;
for(;i<10;i++)
{
linkNode->next = (node *) malloc(sizeof(node));
linkNode->next->prev = linkNode;
linkNode = linkNode->next;
linkNode->next = 0;
linkNode->x = i;
hdd->count+=1;
hdd->tl = linkNode;
}
linkNode = hdd->hd;
printf("priniting in next direction\n");
while(linkNode!=0)
{
printf("%d\n",linkNode->x);
linkNode = linkNode->next;
}
linkNode = hdd->tl;
printf("priniting in prev direction\n");
while(linkNode!=0)
{
printf("%d\n",linkNode->x);
linkNode = linkNode->prev;
}
linkNode = hdd->hd;
while(linkNode!=0)
{
free(linkNode->prev);
linkNode = linkNode->next;
}
free(hdd);
}
Your linked list looks something like this:
+------+----+----+
| Head | hd | tl | ---------->--------
+------+----+----+ \
| ---->------ | NULL
| / \ | |
+------+-----+------+------+ +------+-----+------+------+
| Node | x=0 | next | prev | | Node | x=1 | next | prev |
+------+-----+------+------+ +------+-----+------+------+
| | |
\ NULL /
-----------------------<----------------------
(I've simplified it to two nodes).
Now, we can just write out what this code does:
linkNode = hdd->hd;
while(linkNode!=0) {
free(linkNode->prev);
linkNode = linkNode->next;
}
linkNode = hdd->hd leaves linkNode pointed at the first node
(linkNode!=0) is true (the first node is not NULL), so we enter the while loop
free(linkNode->prev) calls free(NULL) since hdd->hd->prev == NULL (you set the first node up like this explicitly). This is fine, but does nothing.
linkNode = linkNode->next leaves linkNode pointed at the last node
linkNode!=0 is still true (the last node is also not NULL), so we go round the loop again
free(linkNode->prev) frees the previous node (which is the first one)
linkNode = linkNode->next leaves linkNode == NULL
linkNode!=0 is false now, so the loop terminates.
So, we free'd all but the last node. No node's prev member points to that node, so calling free(linkNode->prev) can never free it. You could, however, free it via hdd->tl.
You are already freeing the memory allocated to your nodes of your linked list in the reverse order from the tail of the list. This line is doing this.
free(linkNode->prev);
There is a memory leak in your program . Your last node in the list is not freed.
Just include
free(linkNode);
before freeing hdd .
Explanation for:
while(linkNode!=0)
This is to make sure that you are dereferencing a NULL pointer. Since dereferncing a NULL pointer could cause undefined behaviours.
These are the dereference operations
linkNode->x
linkNode->prev

Resources