Related to pointers in C - c

void pushathead(struct Node* head, int data){
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = data;
new_node->next = head;
head = new_node;
}
void pushathead(struct Node** head, int data){
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = data;
new_node->next = (*head);
(*head) = new_node;
}
Can anyone explain the difference between the two methods, and which one should be used for implementation?

The first implementation accepts a pointer argument to the head of your linked list.
The second implementation accepts a pointer to a pointer to the head of your linked list.
Can you tell why that might be important?
You want to use the second one, otherwise you will lose any reference to the new node being created.
In other words, the first implementation is just modifying a local copy of head, the last line head = new_node; is meaningless, doing effectively nothing because it's working on a local value. The second implementation will modify a pointer on the outside.
First will be called like this:
Node *head = NULL; // declared somewhere
pushathead( head, 1 );
And the second will be called like this:
Node *head = NULL;
pushathead( &head, 1 );
Using the address-of operator here is a big hint that head is going to be modified, and that's what you want.

I'd go for a third choice:
struct Node* pushathead(struct Node* head, int data){
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = data;
new_node->next = head;
return new_node;
}
and use it like this:
Node *list = NULL; // declared somewhere
list = pushathead( list, 10 );
list = pushathead( list, 20 );

Related

Reference to non-NULL value NULL after assignment

I'm implementing a singly linked list using C.
struct Node
{
int nodeValue;
struct Node* pNext;
};
struct Node* head;
void createList()
{
head = (struct Node*)malloc(sizeof(struct Node));
}
void insertNodeAtBeginning(int value)
{
struct Node* newNode;
newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->nodeValue = value;
struct Node* auxNode;
if(head->pNext == NULL)
{
head->pNext = newNode;
}
else
{
auxNode = head->pNext;
head->pNext = newNode;
newNode->pNext = auxNode; //breakpoint set here
}
}
I've set a breakpoint on line marked by the comment. The value of auxNode is non-NULL:
(gdb) p auxNode
$4 = (struct Node *) 0x5555555551db <createList+18>
However the value of newNode->pNext to which the auxNode is assigned is NULL:
(gdb) p newNode->pNext
$5 = (struct Node *) 0x0
Could anyone clarify this behavior? Thanks.
For starters the function createList does not make a sense.
void createList()
{
head = (struct Node*)malloc(sizeof(struct Node));
}
You already created an empty list
struct Node* head;
Within the function data members nodeValue and pNext were not initialized,
The function insertNodeAtBeginning also does not make a sense because at least it does not insert a node at beginning due to this code snippet
if(head->pNext == NULL)
{
head->pNext = newNode;
}
Moreover it invokes undefined behavior because the data member pNext of the node pointed to by the pointer head was not initialized. And again you forgot to initialize the data member pNext of the new node when head->pNext is equal to NULL.
Remove the function createList and define the function insertNodeAtBeginning the following way
int insertNodeAtBeginning(int value)
{
struct Node* newNode = malloc( sizeof( struct Node ) );
int success = newNode != NULL;
if ( success )
{
newNode->nodeValue = value;
newNode->pNext = head;
head = newNode;
}
return success;
}
It appears that you want to maintain your head node, but insert between the head node and the node after the head node, correct? If that is the case, then aside from a misleading function name (perhaps insertNodeAfterHead would be more appropriate), you should initialize your head struct members after you allocate with malloc.
Should be...
void createList()
{
head = (struct Node*)malloc(sizeof(struct Node));
head->nodeValue = 0
head->pNext = NULL;
}

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
}

C - Singly linked list - passing a pointer by value vs by reference

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.

Inserting In a Doubly LinkedList

I am trying to insert into a doubly linked list. I am then trying to print the list in both forward and reverse direction. I have created a head node and I am trying to insert another one, but I am unable to do so. The program shows a runtime error.
Please find my code below. Any help would be appreciated.
#include<stddef.h>
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
struct node *prev;
};
void insertAfter(struct node *node, int new_data){
if (node == NULL)
{
printf("the given previous node cannot be NULL");
return;
}
struct node* new_node = (struct node*)malloc(sizeof(struct node));
node->data = new_data;
node->next = new_node;
new_node->prev = node;
new_node->next - node->next;
if(new_node->next!=NULL)
new_node->next->prev = new_node;
}
void printlist(struct node *node){
struct node *last;
printf("Traversal in forward direction\n");
while(node!=NULL){
printf("%d\n",node->data);
last = node;
node=node->next;
}
printf("Traversal in backward direction\n");
while(last!=NULL){
printf("%d\n",last->data);
last=last->prev;
}
}
int main()
{
struct node *head;
struct node *tail;
head->data = 5;
tail->data = 10;
head->next = tail;
head->prev = NULL;
tail->next = NULL;
insertAfter(head, 8);
printf("\n Created DLL is: ");
printlist(head);
return 0;
}
There are several problems here.
First, as pointed out by #Igor, you are not allocating any memory for your head and tail nodes. You should also set tail->prev = head.
Second, the order in which insertAfter sets the link pointers causes node->next to be overwritten before it is used in setting new_node->next. This causes new_node->next to point back to new_node instead of to whatever was following node. You should set new_node->next and new_node->prev before you modify node. It also appears that you have used a minus sign instead of an equals in the "assignment" of new_node->next.
Third, in printlist, you should initialize last to NULL in case the list is empty; otherwise, you will attempt to walk the list backwards from an undefined starting (ending) point.
You want new_node->next to be the same as new_node?
if not, you'd better swap these two lines, in InsertAfter:
node->next = new_node;
new_node->next - node->next;
You need to allocate memory for your pointers head and tail.
int main()
{
struct node *head;
struct node *tail;
head = malloc(sizeof(struct node)); //allocating memory to head
tail = malloc(sizeof(struct node)); //allocating memory to tail
head->data = 5;
tail->data = 10;
head->next = tail;
head->prev = NULL;
tail->next = NULL;
insertAfter(head, 8);
printf("\n Created DLL is: ");
printlist(head);
return 0;
}
Also, never cast the return value of malloc, therefore change:
struct node* new_node = (struct node*)malloc(sizeof(struct node));
to
struct node* new_node = malloc(sizeof(struct node));

Append an element at the end of a linked-List in C programming

I've been studying linked lists in C and regarding the append function, I came across the following code:
struct node
{
int data;
struct node *next;
}*head;
void append(int num)
{
struct node *temp,*right;
temp= (struct node *)malloc(sizeof(struct node));
temp->data=num;
right=(struct node *)head;
while(right->next != NULL){
right=right->next;
}
right->next =temp;
right=temp;
right->next=NULL;
}
In order to save a line of code, wouldn't it be possible to just add NULL to the temp's next atribute? like so:
void append(int num)
{
struct node *temp,*right;
temp= (struct node *)malloc(sizeof(struct node));
temp->data=num;
temp -> next = NULL;
right=(struct node *)head;
while(right->next != NULL){
right=right->next;
}
right->next =temp;
}
Yes you are correct. In-fact I will further reduce the length of code by writing separate function that allocate and intialize data as follows:
struct node * getnode(int date){
struct node *temp = malloc(sizeof(struct node));
temp->data = data;
temp->next = NULL;
return temp;
}
// assuming list have more than one elements: demo code
void append(struct node *head, int num){
struct node *right = head;
while(right->next != NULL){
right=right->next;
}
right->next = getnode(num);
}
This get node function can be useful in other part of code e.g insertatfist(), insert()
Btw: Don't cast the returned address of malloc() and calloc().
May be you like to write struct node* getnode(int data, struct node* next) function that also set next node address.
call it as:
To insert last node:
curt->next = getnode(num, NULL);
To insert between curt node and curt->next.
curt->next = getnode(num, curt->next);
It certainly is possible to do it that way in this way, However, I see that the code in the first approach is more readable(very small more) to my eyes. However you aren't going to save much.
But don't try to do these kind of optimizations for all programs, give readability more importance than saving a few lines of code. Reason is that compiler is anyways going to do the optimization.
If you want to "save lines", you could also use calloc, instead of malloc, which zeros your bytes,
but that would be LESS clear.
It does save you a line of code, and it is arguable clearer.
I think your proposed code change is an improvement in that it separates creation of the new node from placing it.
If this is production code I would probably let sleeping dogs lie. But while we are all chiming in here is how I would implement the same function.
struct node
{
int data;
struct node *next;
};
struct node* init_node(int num)
{
struct node * temp = malloc(sizeof(struct node));
temp->data = num;
return temp;
}
void append(struct node* n, struct node* list)
{
while(list->next != NULL){
list=list->next;
}
list->next =n;
n->next=NULL;
}

Resources