Pointer return by a function in C - c

Following is the code for making a linked list which has 2 pointers. Linked list is getting created (printed) and all pointers (prev + next) are fine. But when I call the function "copay" and assign its value(pointer) to "duplicate", I am getting segmentation fault but if I use only "copay" and don't assign it to any other variable then there is no issue.
typedef struct node {
int data;
struct node *next;
struct node *prev;
} node;
void insert(node **head, int data) {
node *new = (struct node *)malloc(sizeof(node));
new->data = data;
new->next = NULL;
node *temp = *head;
if (!(temp)) {
*head = new;
new->prev = NULL;
// printf("\n return : %d",data);
return;
}
while (temp->next)
temp = temp->next;
temp->next = new;
new->prev = temp;
// printf("\n return : %d",data);
}
void print(node **head) {
node *temp = *head;
printf("\n");
while (temp) {
printf(" %d ->", temp->data);
temp = temp->next;
}
printf(" NULL\n");
}
node *copay(node **head) {
node *temp = *head;
return temp;
}
int main() {
node *head;
insert(&head, 1);
insert(&head, 3);
insert(&head, 5);
insert(&head, 7);
insert(&head, 9);
(head)->prev = (head)->next->next;
(head)->next->next->prev = (head)->next->next->next->next;
(head)->next->next->next->next->prev = (head)->next;
print(&head);
node *duplicate = copay(&head);
// print(&duplicate);
}

There is a very simple problem in function main():
node *head;
head is defined but not initialized. You must initialize it to NULL for insert() to function properly, otherwise you have undefined behaviour. Incidentally, it is confusing to name insert a function that actually appends a node to a list. Change this line to:
node *head = NULL;
I do not understand you you are trying to achieve with these lines:
(head)->prev = (head)->next->next;
(head)->next->next->prev = (head)->next->next->next->next;
(head)->next->next->next->next->prev = (head)->next;
The rest looks fine to me.

copay() is actually fine while it is running. The problem happens to its caller(here it is main function) after copay() exits. copay() returns a pointer to a node, but the problem is that the local node, temp, is allocated only while copay() is running. When copay() exits, all of its locals are deallocated. So the caller is left with a pointer to a deallocated node.
I would refer you to go through Section 2 of Pointers and Memory from Stanford CS Education Library which is on Local Memory.
Source: Pointers and Memory

Related

Why deleting a node in linked list fails when explicitly using a variable to save the head of the list?

I'm using this function to create a list by pushing a new node to the front.
void push(struct Node **head, int newValue)
{
if (*head == NULL)
{
puts("List is empty. The first node will be created now... ");
}
struct Node *new_node = malloc(sizeof(struct Node));
new_node->data = newValue;
new_node->next = (*head);
(*head) = new_node;
}
I'm populating the list by doing this:
push(&head, 10);
push(&head, 20);
push(&head, 30);
push(&head, 40);
This gives me the following list: 40->30->20->10
Now, I want to delete the element at the head of the list. Here's my delete function:
void delete (struct Node **head, int key)
{
// struct Node *currentNode = (*head);
if ((*head)->data == key)
{
struct Node *tmp = (*head);
(*head) = (*head)->next;
free(tmp);
}
}
Then:
delete(&head, 40);
printList(head);
and I get the expected output (i.e. 30->20->10).
However, if I un-comment the struct Node *currentNode = (*head); line and use the currentNode pointer instead of (*head) like so:
void delete (struct Node **head, int key)
{
struct Node *currentNode = (*head);
//if the key is at HEAD (the first node)
if (currentNode->data == key)
{
struct Node *tmp = currentNode;
currentNode = currentNode->next;
free(tmp);
}
}
, and I call delete(&head, 40) and printList(&head) again, Iget some values that I believe are garbage (i.e. 0->1).
My printList is this:
void printList(struct Node *list)
{
int index = 0;
while (list != NULL)
{
index++;
list = list->next;
}
}
and Node is this:
struct Node
{
int data;
struct Node *next;
};
What's going on?
Update
For this struct,
struct Test
{
int x;
};
int main()
{
struct Test *myPtr = malloc(sizeof(struct Test));
myPtr->x = 111;
printf("Before copyStructOne x is: %d\n", myPtr->x);
copyStructOne(&myPtr);
//would expect this print 111 and not 500
printf("After copyStructOne x is: %d\n", myPtr->x);
}
void copyStructOne(struct Test **testPtr)
{
//doesn't this create a local copy like in my original question?
struct Test *testStr = (*testPtr);
testStr->x = 500;
printf("Inside copyStructOne x is: %d\n", testStr->x);
}
In the case where you're using currentNode, it contains a copy of what is in *head. However, you only modify the copy, not *head, so the head of the list doesn't actually change. So after the function returns, head now points to memory that has been freed, so reading that pointer triggers undefined behavior.
The reason for passing a pointer-to-pointer is to allow a pointer in the calling function to be modified by the called function.
In fact what you have in the modified function is similar to the following
int x = 10;
int y = x;
y = 0;
After this code snippet the variable x stays unchanged because it is the variable y that initially was initialized by the value of the variable x that was changed.
There is no need to introduce the local variable currentNode within the function.
I suspect that you want to change the function such a way that it would delete any node (not only the first one) that has a value equal to the value of the parameter key.
In this case the function can look the following way
int delete (struct Node **head, int key)
{
while ( *head != NULL && ( *head )->data != key )
{
head = &( *head )->next;
}
int success = *head != NULL;
if ( success )
{
struct Node *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
return success;
}

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.

reverse linked list in C using recursion

I have written following code in C. I am pretty new to C. The insert and Print functions seem to work fine but I get a prompt that says program stopped working when I call Reverse function.
Where dis I go wrong ?
//WAP to reverse a Linked List using recursion
#include<stdio.h>
#include<stdlib.h>
struct Node{
int data;
struct Node* next;
};
struct Node* head; //global variable
struct Node* Reverse(struct Node* p){
if(p->next == NULL){ //since for last node link part is null
head = p;
printf("break condition");
return head;
}
printf("calling reverse");
Reverse(p->next);
struct Node* q = p->next;
q->next = p;
p->next = NULL;
}
void Insert(int x){
struct Node* temp= (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
//temp->next = NULL; //redundant
//if(head!= NULL){
temp->next = head; //temp.next will point to null when head is null nd otherwise what head was pointing to
//}
head = temp;
}
void Print(){
struct Node* temp1 = head; //we dont want tomodify head so store it in atemp. bariable and then traverse
while(temp1 != NULL){
printf(" %d", temp1->data);
temp1= temp1->next;
}
printf("\n");
}
int main(){
struct Node* head = NULL;
Insert(2);
Insert(4);
Insert(5);
Insert(1);
Print();
head = Reverse(head);
// Print();
}
There are two issues with the program above:
1) You have two head variables. One is a global variable, and the other is a variable local to the main function. That local variable is the one that is passed to Reverse(). Since the first thing that function does is dereferencing it, the program crashes. Removing the local head variable in the main() function should address it.
2) The Reverse() function correctly returns head when it reaches the exit condition, but what happens the rest of the time? It's missing a return in the non-exit condition case. Here's a diff that would address the issue:
printf("calling reverse");
- Reverse(p->next);
+ struct Node* ret;
+ ret = Reverse(p->next);
struct Node* q = p->next;
q->next = p;
p->next = NULL;
+ return ret;

Adding node to singly linked list not working properly

I have a singly linked list struct and a local Node declared in main with my addToList() function, but every time addToList() executes it runs the case (head == NULL). Even when I already added values to the list. I am sure there is a small bug in my code, I just can't find it.
typedef struct node{
char* name;
int groupSize;
int status;
struct node* next;
}Node;
void addToList(char* name, Node* head, int groupSize, int status){
if(head == NULL){
head =(Node*)malloc(sizeof(Node));
head->name = (char*) malloc(sizeof(char)*30);
strcpy(head->name, name);
head->groupSize = groupSize;
head->status = status;
head->next = NULL;
printf("Name is %s\n\n", head->name);
}
else {
printf("entered else\n");
Node *tmp = head;
if(tmp->next!=NULL){
tmp = tmp->next;
}
tmp->next = (Node*) malloc(sizeof(Node));
tmp->next->name = (char*) malloc(sizeof(char)*30);
strcpy(tmp->next->name, name);
tmp->next->groupSize = groupSize;
tmp->next->status = status;
tmp->next->next = NULL;
}
}
int main(){
Node* head = NULL;
//TESTNG SECTION
addToList("Julio", head, 5, 7);
addToList("Francisco", head, 5, 7);
addToList("Jorge", head, 5, 7);
}
The cause of your problem is the call by value of every C function call.
At the first call of addToList(), head of the main() points to NULL.
Inside the addToList() you change the parameter head to point to a newly allocated memory region. Unfortunately, by the time addToList() returns the scope of the parameter head does not exist any more. So the head variable at the main, has exactly the same value prior the addToList() call.
The solution to this problem would be the use of double pointer for the head, or return and assign at every call the head of the list. So because previous answer covered the one solution, I will provide the other.
Node* addToList(char* name, Node* head, int groupSize, int status){
if(head == NULL){
head =(Node*)malloc(sizeof(Node));
head->name = (char*) malloc(sizeof(char)*30);
strcpy(head->name, name);
head->groupSize = groupSize;
head->status = status;
head->next = NULL;
printf("Name is %s\n\n", head->name);
}
else {
printf("entered else\n");
Node *tmp = head;
if(tmp->next!=NULL){
tmp = tmp->next;
}
tmp->next = (Node*) malloc(sizeof(Node));
tmp->next->name = (char*) malloc(sizeof(char)*30);
strcpy(tmp->next->name, name);
tmp->next->groupSize = groupSize;
tmp->next->status = status;
tmp->next->next = NULL;
}
return head;
}
int main(){
Node* head = NULL;
//TESTNG SECTION
head = addToList("Julio", head, 5, 7);
head = addToList("Francisco", head, 5, 7);
head = addToList("Jorge", head, 5, 7);
}
The head parameter will be initialized inside the function, you have to pass a pointer to a Node pointer :
void addToList(char* name, Node** head, int groupSize, int status);
Then :
*head =(Node*)malloc(sizeof(Node));
Explanations by Manos.
There are a few small problems that I see with your code.
First, I would use different names when passing in the head pointer. It might be confusing the compiler on where to look. Also, when you pass in a node pointer in addToList, you need to dereference it, so instead pass in Node**, and initialize a pointer within the method.
Second, in your addToList method, you have the following condition:
if(tmp->next!=NULL){
tmp = tmp->next;
}
this will only work when you have 2 elements in your list. Instead, make it a while loop, like so:
while(tmp->next!=NULL){
tmp = tmp->next;
}
This will correctly place the tmp pointer at the end of your list.
Hopefully this will fix some bugs,

C: How to free nodes in the linked list?

How will I free the nodes allocated in another function?
struct node {
int data;
struct node* next;
};
struct node* buildList()
{
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
head = malloc(sizeof(struct node));
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 1;
head->next = second;
second->data = 2;
second->next = third;
third->data = 3;
third->next = NULL;
return head;
}
I call the buildList function in the main()
int main()
{
struct node* h = buildList();
printf("The second element is %d\n", h->next->data);
return 0;
}
I want to free head, second and third variables.
Thanks.
Update:
int main()
{
struct node* h = buildList();
printf("The element is %d\n", h->next->data); //prints 2
//free(h->next->next);
//free(h->next);
free(h);
// struct node* h1 = buildList();
printf("The element is %d\n", h->next->data); //print 2 ?? why?
return 0;
}
Both prints 2. Shouldn't calling free(h) remove h. If so why is that h->next->data available, if h is free. Ofcourse the 'second' node is not freed. But since head is removed, it should be able to reference the next element. What's the mistake here?
An iterative function to free your list:
void freeList(struct node* head)
{
struct node* tmp;
while (head != NULL)
{
tmp = head;
head = head->next;
free(tmp);
}
}
What the function is doing is the follow:
check if head is NULL, if yes the list is empty and we just return
Save the head in a tmp variable, and make head point to the next node on your list (this is done in head = head->next
Now we can safely free(tmp) variable, and head just points to the rest of the list, go back to step 1
Simply by iterating over the list:
struct node *n = head;
while(n){
struct node *n1 = n;
n = n->next;
free(n1);
}
One function can do the job,
void free_list(node *pHead)
{
node *pNode = pHead, *pNext;
while (NULL != pNode)
{
pNext = pNode->next;
free(pNode);
pNode = pNext;
}
}
struct node{
int position;
char name[30];
struct node * next;
};
void free_list(node * list){
node* next_node;
printf("\n\n Freeing List: \n");
while(list != NULL)
{
next_node = list->next;
printf("clear mem for: %s",list->name);
free(list);
list = next_node;
printf("->");
}
}
You could always do it recursively like so:
void freeList(struct node* currentNode)
{
if(currentNode->next) freeList(currentNode->next);
free(currentNode);
}

Resources