Insert at the back of a singly linked in C - c

Below is my node struct declaration and my insert at the back function. In main, I declare a head node and point it to NULL. Then I call the function, and try to print out the value of the first node but my program stops. I still can't figure out what is wrong.
typedef struct node {
int val;
struct node *next;
} NODE;
void insert_back(NODE *head, int val) {
NODE *new = malloc(sizeof(NODE));
new->val = val;
new->next = NULL;
if (head == NULL)
head = new;
else {
NODE *p = head;
while (p->next != NULL)
p = p->next;
p->next = new;
}
}
int main() {
NODE *head = NULL;
insert_back(head, 2);
printf("%d", head->val);
}

The pointer which you allocate in insert_back is lost when you get out of your function. In order for this to work, your insert_back should get pointer-to-pointer.
typedef struct node {
int val;
struct node *next;
} NODE;
void insert_back(NODE **head, int val) {
NODE *new = malloc(sizeof(NODE));
new->val = val;
new->next = NULL;
if (*head == NULL)
*head = new;
else {
NODE *p = *head;
while (p->next != NULL)
p = p->next;
p->next = new;
}
}
int main() {
NODE *head = NULL;
insert_back(&head, 2);
printf("%d", head->val);
}

You need to pass the address of the head and not just head. Instead of call by value use call by reference
should be something like insert_back(&head, 2);
And in definition change to void insert_back(NODE **head, int val) {

C passes everything by value. You're passing head, which is a null-pointer (as in value NULL) to the insert_back function.
This NULL is assigned to the head argument-variable of that value.
You're altering that variable, which is local to the insert_back function, which is fine, but don't expect to be altering the variable in the main function, too.
There's 2 possible approaches:
Either add a second level of indirection (pass a pointer to the variable you want to alter), or return the head variable, and reassign:
pointer-to-pointer:
void insert_back(NODE **head, int val)
{
NODE *node = malloc(sizeof *node);
if (node == NULL)//check if malloc was successful!
exit(1);//or fprintf(stderr, "message"); and handle the issue
node->val = val;
node->next = NULL;
if (*head == NULL)
{
*head = node;
return;
}
NODE *tmp = *head;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = node;
}
Call this function as you are doing now, but pass the address of the pointer, rather than the pointer itself:
NODE *head = malloc(sizeof *head);
if (head == NULL) exit (1);
head->next = NULL;
insert_back(&head, 123);
Returning head:
NODE * insert_back(NODE *head, int val)
{
NODE *node = malloc(sizeof *node);
if (node == NULL) exit (1);
node->val = val;
node->next = NULL;
if (head == NULL)
{
return node;//head is null, no need to assign
}
NODE *tmp = head;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = node;
return head;//return node passed initially, because it will be reassigned!
}
//call like so:
head = insert_back(head, 123);
As an added bonus, you can use this function to allocate a new struct, too:
NODE *head = insert_back(NULL, 123);//pass null pointer, will return new node and assign it to head
But, equally valid:
NODE *head = insert_back(NULL, 123);
head = insert_back(head, 456);
head = insert_back(head, 789);
printf("Head: %d\nNext: %d\nTail: %d\n",
head->val,
head->next->val,
head->next->next->val
);
Of course, don't forget to write a decent function to free your linked lists.
Perhaps, if you haven't written this already, here's a basic example (again: both methods can be used, but I'd recommend the pointer-to-pointer approach):
void free_list(NODE **list)
{
if (*list->next == NULL)
{//tail
free(*list);
*list = NULL;//assign NULL, makes a valid NULL pointer
return;
}
free_list(&(*list->next));//recursive call
//once we get here, all next-nodes are freed:
free(*list);//free node, and again:
*list = NULL;//make a valid null pointer
}
//call:
free_list(&head);
free(head);//will not be a problem, head is NULL pointer
Alternatively:
void * free_list(NODE *list)
{//note VOID POINTER is returned (will always return NULL, though)
if (list->next == NULL)
{
free(list);
return NULL;
}
free_list(list->next);
free(list);//free node, and again:
return NULL;//make a valid null pointer
}
//call
head = free_list(head);
free(head);//not an issue here
So both are equally safe, you might think, but what if you forget to assign the return value of the second free_list function?
free_list(head);
free(head);//<--X undefined behaviour
The memory head points to has already been freed, but you're calling free a second time. That's going to give you grief: the head pointer is invalid, passing an invalid pointer to free results in undefined behaviour. That's why the first (pointer-to-pointer) approach is the safer option: The function, once written, will never forget to assign NULL to the pointer.
As an asside, a couple of tips:
your main function doesn't return an int. compile this code with -Wall and fix that issue by adding a return 0; statement.
Check the return value of all functions, including malloc & co, if the allocation failed, it will return NULL. You're not checking for that, so there is a risk of undefined behaviour there.

Related

Trying to remove last element from linked list and save it into a variable passed as parameter giving segfault

I have a linked list in which I am trying to remove the last element that is a char* and set the parameter I pass into that function to the char*. However, this either gives a segfault or prints out gibberish. Why is this happening?
Here is the linked list:
struct list_node {
char* name;
struct list_node* next;
};
typedef struct list_node node;
And here are its functions (I'm pretty sure the other functions work but not the remove_last):
int remove_last(node* head, char* ret) {
while(head) {
if (head->next->next == NULL) {
printf("here\n");
ret = strdup(head->next->name);
printf("%s\n", ret);
printf("there\n");
//free(head->next);
//head->next = NULL;
return 0;
}
head = head->next;
}
return -1;
}
void add_last(char* name, node* current) {
node* new_node;
new_node = (node*)malloc(sizeof(node));
while(current) {
if (current->next == NULL) {
current->next = new_node;
new_node->name = name;
return;
}
current = current->next;
}
}
node* add_first(char* name, node* head) {
node* new_node;
new_node = (node*)malloc(sizeof(node));
new_node->name = name;
new_node->next = head;
head = new_node;
return head;
}
Inside the function, when I printf ret, I get what I am supposed to get, but in my main when I try to print out the ret variable I pass into parameters:
char *temp = NULL;
remove_last(head, temp);
printf("%s\n", temp);
I get a segfault. I originally thought maybe it was because I was setting the nodes and freeing them, but I also used strdup (which I think copies it to a new location or smth like that?). I think it might also have something to do with how I am setting temp to null and then I am not setting assigning ret = name correctly in the function? Any advice?
For starters the function add_last is incorrect and can invoke undefined behavior.
Firstly it does not check whether the pointer current (I suppose it can be a pointer to the head node) is equal to NULL. In this case there is a memory leak because the newly created node is not appended to the list.
Secondly the function does not set the data member next of the newly created node to NULL
At least the function can be declared and defined the following way if to use your approach to implementing the function add_first
node * add_last(char* name, node *head ) {
node* new_node;
new_node = (node*)malloc(sizeof(node));
new_node->name = name;
new_node->next = NULL;
if ( head == NULL )
{
head = new_node;
}
else
{
current = head;
while ( current->next ) current = current->next;
current->next = new_node;
}
return head;
}
As for the function remove_last then the function parameter ret is a local variable of the function that will not be alive after exiting the function. The function parameter must have the type char **. That is the corresponding argument must be passed by reference to the function.
And in any case the function is incorrect because it ignores a case when the list contains only one node. You need to pass the pointer to the head node also by reference.
The function can look the following way.
int remove_last( node **head, char **ret )
{
int result = *head == NULL ? -1 : 0;
if ( result == 0 )
{
while( ( *head )->next != NULL ) head = &( *head )->next;
*ret = strdup( ( *head )->name );
free( *head );
*head = NULL;
}
return result;
}

Linked list in C – methods

Suppose we have doubly linked list of nodes
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node* next;
struct Node* prev;
} Node;
typedef struct LinkedList {
Node *first;
Node *last;
} LinkedList;
void initList(LinkedList* l) {
l->first = NULL;
l->last = NULL;
}
and I have to code method, which inserts a new node with given value to the end of the list and returns a pointer to the new node. My attempt follows:
Node *insert(LinkedList *list, int value) {
Node node;
node.value = value;
node.prev = list->last;
node.next = NULL;
if (list->last != NULL){
(list->last)->next = &node;
}else{
list->first = &node;
list->last = &node;
}
return &node;
}
It seems, that insertion in the empty list works, but it doesn't for a non-empty one.
(There are implementation tests, which tell me if an insertion was successful or not. I can post the codes of them, but don't think it's important).
So please, where are the mistakes?
There is a warning in the log (the 51st line is that with 'return &node')
C:\...\main.c|51|warning: function returns address of local variable [-Wreturn-local-addr]|
Is that serious problem? And how to remove it?
Thank you for the answers, but I think there is still a problem with non-empty lists, because according to the test, this fails:
void test_insert_nonempty(){
printf("Test 2: ");
LinkedList l;
initList(&l);
Node n;
n.value = 1;
n.next = NULL;
l.first = &n;
l.last = &n;
insert(&l, 2);
if (l.last == NULL) {
printf("FAIL\n");
return;
}
if ((l.last->value == 2) && (l.last->prev != NULL)) {
printf("OK\n");
free(l.last);
}else{
printf("FAIL\n");
}
}
Node node; is a local variable in your function insert. It is "destroyed" as soon as your function terminates and is not longer defined. Returning a pointer to local variable of a function is undefined behavior. You have to allocate dynamic memory. Dynamically allocate memory is reserved until you free it:
Node *insert(LinkedList *list, int value) {
Node *node = malloc( sizeof( Node ) ); // allocate dynamic memory for one node
if ( node == NULL )
return NULL; // faild to allocate dynamic memory
node->value = value;
node->prev = list->last;
node->next = NULL;
if ( list->first == NULL )
list->first = node; // new node is haed of list if list is empty
else // if ( list->last != NULL ) // if list->first != NULL then list->last != NULL
list->last->next = node; // successor of last node is new node
list->last = node; // tail of list is new node
return node;
}
Note to avoid memory leaks you have to free each node of the list, when you destroy the list.
You are returning address of non-static local variable which will vanish on returning from function, and dereferencing the address after returning from the function invokes undefined behavior.
You have to allocate some buffer and return its address.
Node *insert(LinkedList *list, int value) {
Node *node = malloc(sizeof(Node));
if (node == NULL) return NULL;
node->value = value;
node->prev = list->last;
node->next = NULL;
if (list->last != NULL){
(list->last)->next = node;
}else{
list->first = node;
list->last = node;
}
return node;
}
You have to allocate the new node dynamically.
Otherwise variable node in your function
Node *insert(LinkedList *list, int value) {
Node node;
//...
is a local variable of the function that will not be alive after exiting the function. As result any pointer to the variable used to access it will be invalid.
The function can look like
Node * insert( LinkedList *list, int value )
{
Node *node = malloc( sizeof( Node ) );
if ( node != NULL )
{
node->value = value;
node->prev = list->last;
node->next = NULL;
if ( list->last != NULL )
{
list->last->next = node;
}
else
{
list->first = node;
}
list->last = node;
}
return node;
}

How can I pass a single pointer to a structure, inside a function and modify that structure variable?

In the below piece of code, I am able to modify the a variable used in main from the function.
#include<stdio.h>
int main()
{
int *a,b=10;
a = &b;
printf("%d\n",*a);
ref(a);
printf("%d\n",*a);
return 1;
}
int ref(int *a)
{
int b = 98;
*a = b;
return 1;
}
whereas, in the below piece of code, I couldnot able to do the same.
I know that we can modify a value which is in the main, from a function by using double pointer. I also know that we can use single pointer to modify, by returning the required address to the main and getting it in the main with the same data type. I just wanted to know whether I can modify a value in the main by passing it as a parameter to the function, only as a single pointer to the (structure) variable.
Note: I have denoted the working code with the comment '//WC'. Will be very thankful if someone can explain me the same.
//int insert(int data, Node **head) //WC
int insert(int data, Node *head)
{
Node *temp, *run;
temp = (Node *) malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
//if(*head == NULL) //WC
if(head == NULL)
{
printf("1st node\n");
//*head = temp; //WC
*head = *temp;
}
else
{
printf("node after first\n");
//run = *head //WC
*run = *head;
while(run->next != NULL)
{
run = run->next;
}
run->next = temp;
}
return 1;
}
int main()
{
Node *head;
insert(10, head);
insert(20, head);
insert(30, head);
insert(40, head);
insert(50, head);
return 1;
}
How can I pass a single pointer to a structure, inside a function and modify that structure variable?
TL;DR : you can modify the value pointed by the pointer, but you cannot modify the passed pointer itself.
C uses pass-by-value for function parameter passing. You cannot change the value of the received parameter from the called function and expect it to reflect in the variable used as the argument from the caller function.
However, in case of pointers, you usually don't modify the pointer itself, rather, we modify the value it points to. So, the changed value pointed by that pointer will be reflected in the caller function.
When you check if head is empty (has NULL value), you need to check the content of head (*head), not head itself since that means its own address. so if (head == NULL), should be *head == Null. head represents memory address of the pointer head and *head represents what is saved in that address(what is pointed to). With that logic, *head = temp; is correct as it will save the address of the dynamically allocated memory address -temp in head however the later one (*head = *temp) will attempt to copy/save content of temp to head which doesn't make sense since head is has only a size of a pointer and temp could be allocated whatever size the node is. I hope I helped at least a little bit and here is a working version of your code :)
int insert(int data, Node **head) //WC, This is correct because the parameter **head takes address of the pointer to the first node if any.
//int insert(int data, Node *head)
{
Node *temp, *run;
temp = (Node *) malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
if(*head == NULL) //WC, checking if head has any address value inside (not its own address)
{
printf("1st node\n");
*head = temp; //WC, because temp has address of the allocated memory and you wanna hold that address as the head / first node.
}
else
{
printf("node after first\n");
run = *head //WC
//*run = *head; you can't use this, one reason is because head could point to any size of memory (e.g 10000kb) and run has a size of a pointer, just few bytes.
while(run->next != NULL)
{
run = run->next;
}
run->next = temp;
}
return 1;
}
(Edit: multiple pointer use might complicate reading so I'd rather use the following struct defination)
typedef struct node* PNode; //Pointer to node
typedef struct node {
int item;
Pnode next;
} Node;
void insert(int data, PNode *head) {
PNode temp, run = *head;
temp = (PNode)malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
if (run == NULL){
*head = temp;
}//first node
else{
while (1) {
if (run->next == NULL) {
run->next = temp;
break;
}
run = run->next;
}
}
}

Program keeps crashing when I destroy my linked list

For some reason, my code keeps crashing.
If anyone can help me find out why, I would be very thankful.
int destroy(struct node *p)
{
struct node * temp = p;
struct node * next;
while (temp->next != NULL)
{
next = temp->next;
free(temp);
temp = next;
}
p = NULL;
return 1;
}
You need to test temp for null-ness, not temp->next:
void destroy(struct node *p)
{
struct node *temp = p;
while (temp != NULL)
{
struct node *next = temp->next;
free(temp);
temp = next;
}
}
You also don't need to set p to null (it doesn't do anything useful). And returning a status is not a good idea. Your callers either have to test it (but will never see anything other than 1, so the test is pointless), or they have to ignore it (in which case, why bother to return it?). You could do without the variable temp, too:
void destroy(struct node *list)
{
while (list != NULL)
{
struct node *next = list->next;
free(list);
list = next;
}
}
If you really want to set the pointer to null, you have to change the notation:
void destroy(struct node **list)
{
struct node *node = *list;
while (node != NULL)
{
struct node *next = node->next;
free(node);
node = next;
}
*list = NULL;
}
and instead of:
struct node *root = ...;
...
destroy(root);
you would have to write:
struct node *root = ...;
...
destroy(&root);

Why is this Linked list code result in always head being null?

I have implemented a short linked list code to add to the beginning of the list.
However the head always contained NULL. I really couldn't get why its behaving in this way. Any help is appreciated ! Below is the code :
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int iData;
struct node *next;
} Node;
void add2Beg(Node* head, int num);
int main(int argc, char const *argv[])
{
Node *head = NULL;
add2Beg(head, 5);
if (head == NULL)
printf("nothing in head !!!\n");
else{
printf("not null\n");
}
add2Beg(head, 15);
return 0;
}
//adds to the beginning of the linked list
void add2Beg(Node* head, int num)
{
//create a temporary location to hold the new entry
Node* temp = (Node *)malloc(sizeof(Node));
temp->iData = num;
if(head == NULL)
{
head = temp;
printf("inside add2Beg\n");
printf("%d\n", head->iData);
head->next = NULL;
printf("exiting add2Beg\n");
}
else
{
temp->next = head;
printf("%p\n", temp->next);
head = temp;
}
}
Because the head variable inside of add2Beg() is local to that function. Assigning a new pointer value to it (head = temp;) only changes the head variable inside the function. You need to pass in a pointer-to-pointer:
void add2Beg(Node** head, int num)
Then use *head inside the function:
if(*head == NULL)
{
*head = temp;
Be careful about lines like head->next = NULL; -- this should be rewritten as (*head)->next = NULL; or (**head).next = NULL;.
And so on. Then call the function like so:
add2Beg(&head, 15);
Because you never assigned head to anything other than NULL...
//here you set it to NULL then pass it to your function
Node *head = NULL;
add2Beg(head, 5);
here in your function you pass in a copy of "head"
void add2Beg(Node* head, int num)
{
//create a temporary location to hold the new entry
Node* temp = (Node *)malloc(sizeof(Node));
temp->iData = num;
if(head == NULL) //we'll get in here
At this point you assign temp to it, so within the scope of this function it's something vaid, but once you leave this function it's back to NULL.
You passed in a copy of the pointer "head" and called it "head". You need to either return the value and assign it in main() or pass a pointer to head into this function in order for the value to be updated.
Solutions:
Node *head = NULL;
head = add2Beg(head, 5);
Node* add2Beg(Node* head, int num){
...
return head;
OR
Node *head = NULL;
add2Beg(&head, 5);
void add2Beg(Node** head, int num){
...
Your function add2beg is not returning the new head in the case when it's modified. Change your function to:
Node * add2Beg(Node* head, int num)
and return the head at the end:
return head;

Resources