Segmentation Fault when creating a queued list of objects - c

Task is to create objects in the main and have them passed to other functions, which will create a list of type queue. That's the algorithm I'm using:
Write a function of type Node * which will return a pointer to the last Node of the list
To insert a Node at the end of the list, it's required to get a pointer to the last Node
Create a new Node
Assign the newly created Node the object that's been passed to the function
Make next from the last Node point the new one
Here's the code:
typedef struct Node{
int val;
char str[30];
struct Node *next;
}Node;
void printList(const Node * head);
void queue(Node *head, Node *object);
Node *getLast(Node *head);
int main(void){
Node *head = NULL;
Node *object = (Node *)malloc(sizeof(Node));
int c = 0;
while(1){
printf("This int will be stored in Node %d.\n", ++c);
scanf("%d", &object->val);
if(!object->val){
puts("You've decided to stop adding Nodes.");
break;
}
fflush(stdin);
printf("This string will be stored in Node %d.\n", c);
fgets(object->str, 30, stdin);
if(!(strcmp(object->str, "\n\0"))){
puts("You've decided to stop adding Nodes.");
break;
}
queue(head, object);
}
printList(head);
return 0;
}
void printList(const Node *head){
if(head == NULL){
puts("No list exists.");
exit(1);
}
while(1){
printf("|||Int: %d|||String: %s|||\n", head->val, head->str);
if(head->next){
head = head->next;
}
else{
break;
}
}
}
Node *getLast(Node *head){
if(head == NULL){
return NULL;
}
while(head->next){
head = head ->next;
}
return head;
}
void queue(Node *head, Node *object){
Node *last = getLast(head);
Node *tmp = (Node *)malloc(sizeof(Node));
*tmp = *object;
tmp -> next = NULL;
last -> next = tmp;
}
Maybe the problem is in having getLast return NULL. But then again, this exact same thing worked when I created a list consisting only of int.

As pointed out in the comment section, last->next = tmp fails for first call to queue() as getLast() returns NULL. A correct solution would be like this:
void queue(Node **head, Node *object){
Node *last = getLast(*head);
Node *tmp = (Node *)malloc(sizeof(Node));
*tmp = *object;
tmp -> next = NULL;
if (last != NULL)
last -> next = tmp;
else
*head = tmp;
}
and call queue(&head, object) from main().

Related

Copying elements of a linked list to another linked list in reverse order in C

I'm new to programming in C and taking a course. I'm having trouble with one of the tasks I'm practicing. I'm supposed to Write a program that creates a linked list of 10 characters, then creates a copy of the list in reverse order. I have written (mostly copied) a code, but it only reverses the contents of my linked list, doesn't copy them to a new linked list in reverse order. It's also not working with letters even though I'm using char data type. works fine with numbers.
Here's my code:
#include <stdio.h>
#include <malloc.h>
struct Node
{
char data;
struct Node *next;
};
static void reverse(struct Node **head_ref)
{
struct Node *previous = NULL;
struct Node *current = *head_ref;
struct Node *next;
while (current != NULL)
{
next = current->next;
current->next = previous;
previous = current;
current = next;
}
*head_ref = previous;
}
void push(struct Node **head_ref, char new_data)
{
struct Node *new_node =
(struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
void printList(struct Node *head)
{
struct Node *temp = head;
while (temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
}
int main()
{
struct Node *head = NULL;
char element = NULL;
printf("Enter 10 characters:\n");
for (int i = 0; i <= 9; i++)
{
scanf_s("%d", &element);
push(&head, element);
}
printf("Given linked list\n");
printList(head);
reverse(&head);
printf("\nReversed Linked list \n");
printList(head);
getchar();
}
This for loop
for (int i = 0; i <= 9; i++)
{
scanf_s("%d", &element);
push(&head, element);
}
invokes undefined behavior because there is used an incorrect conversion specifier %d with an object of the type char,
You need to write
for (int i = 0; i <= 9; i++)
{
scanf_s( " %c", &element, 1 );
push(&head, element);
}
Pay attention to the blank before the conversion specifier %c in the format string. This allows to skip white space characters in the input stream.
As for the function then it can be declared and defined the following simple way using the function push that you already defined
struct Node * reverse_copy( const struct Node *head )
{
struct Node *new_head = NULL;
for ( ; head != NULL; head = head->next )
{
push( &new_head, head->data );
}
return new_head;
}
And in main you can write something like
struct Node *second_head = reverse_copy( head );
Take into account that the function push would be more safer if it would process the situation when memory allocation for a node failed.
To create a copy in reverse order, create a new list with the same values as the original list but prepend the new nodes using the push function.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct Node {
char data;
struct Node *next;
};
void prepend(struct Node **head_ref, char new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
void append(struct Node **head_ref, char new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
struct Node *node = *head_ref;
new_node->data = new_data;
new_node->next = NULL;
if (!node) {
*head_ref = new_node;
} else {
while (node->next)
node = node->next;
node->next = new_node;
}
}
void printList(const struct Node *head) {
const struct Node *temp = head;
while (temp != NULL) {
printf("%c ", temp->data);
temp = temp->next;
}
printf("\n");
}
struct Node *copy_reverse(struct Node *list) {
struct Node *new_list = NULL;
while (list) {
prepend(&new_list, list->data);
list = list->next;
}
return new_list;
}
void freeList(struct Node *list) {
while (list) {
struct Node *node = list;
list = list->next;
free(node);
}
}
int main() {
struct Node *head = NULL;
char element;
printf("Enter 10 characters:\n");
for (int i = 0; i < 10; i++) {
scanf_s("%c", &element);
push(&head, element);
}
printf("Given linked list\n");
printList(head);
struct Node *copy = copy_reverse(head);
printf("\nReversed Linked list \n");
printList(copy);
freeList(head);
freeList(copy);
getchar();
}
You're almost there. All it needs is one tweak. In reverse, you need to create a new copy of the current node and use that instead. Also, since you'll be ending up with a second list and not altering the original, you should return the new list from reverse.
static struct Node* reverse(const struct Node* head_ref)
{
struct Node* previous = NULL;
const struct Node* current = head_ref;
struct Node* copy;
while (current != NULL) {
copy = malloc(sizeof(*copy));
if (copy == NULL) {
// handle error
}
copy->data = current->data;
copy->next = previous;
previous = copy;
current = current->next;
}
return previous;
}
You can also make the loop prettier by converting it to a for loop.
for (current = head_ref; current != NULL; current = current->next) {
Finally, when you print out the list, you're using %d in the printf format string. %d will print the char as an integer. To print out the actual character, use %c instead.

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;
}

Adding a node at the beginning of a Singly Linked List (C)

The code works without error but I cant seem to know why the new node is not being inserted to the beginning of the list. It probably has something to do with the else statement in the first function (insertNode) but I'm not sure, what's going on?
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *link;
};
void insertNode(struct node *head, int x) {
//Create node to be added and add the input integer to it
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = x;
//Check if there are any existing nodes in the list, if not, the let the head be equal to the new temp pointer
if (head == NULL) {
head = temp;
} else {
//If not, then we need to add the node to the beginning
temp->link = head;
head = temp;
printf("Node was added successfully!\n");
}
}
int findsize(struct node *head) {
//Finds the size of the list
struct node *temp = head;
int count = 0;
while (temp != NULL) {
count++;
temp = temp->link;
}
return count;
}
void printData(struct node *head) {
//Prints the elements of the list
struct node *temp = head;
while (temp != NULL) {
printf("Element: %d\n", temp->data);
temp = temp->link;
}
}
void main() {
//Created a node and allocated memory
struct node *head;
head = (struct node *)malloc(sizeof(struct node));
//Added data to the node and created another one linked to it
head->data = 15;
head->link = (struct node *)malloc(sizeof(struct node));
head->link->data = 30;
head->link->link = NULL;
//Used the above function to add a new node at the beginning of the list
insertNode(head, 5);
//Print the size of the list
printf("The size of the list you gave is: %d\n", findsize(head));
//Print the elements of the list
printData(head);
}
When you insert a node at the beginning of the list, you effectively change the beginning of the list, so this new initial node must be returned to the caller. The prototype for insertNode() must be changed to return the list head or to take a pointer to the list head.
Here is a modified version with the first approach:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *link;
};
struct node *insertNode(struct node *head, int x) {
//Create node to be added and add the input integer to it
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
if (temp != NULL) {
temp->data = x;
temp->link = head;
}
return temp;
}
int findsize(struct node *head) {
//Find the size of the list
struct node *temp = head;
int count = 0;
while (temp != NULL) {
count++;
temp = temp->link;
}
return count;
}
void printData(struct node *head) {
//Prints the elements of the list
struct node *temp = head;
while (temp != NULL) {
printf("Element: %d\n", temp->data);
temp = temp->link;
}
}
void main() {
//Created a node and allocated memory
struct node *head = NULL;
//Insert 3 nodes with values 30, 15 and 5
head = insertNode(head, 30);
head = insertNode(head, 15);
head = insertNode(head, 5);
//Print the size of the list
printf("The size of the list you gave is: %d\n", findsize(head));
//Print the elements of the list
printData(head);
//Should free the nodes
return 0;
}

Insertion at end in linked list

I am inserting node at the end of the list but my code is printing only the first element and running in infinite loop.
I am unable to figure out the error in my code.
typedef struct nodetype
{
int info;
struct nodetype* next;
}node;
node *head=NULL;
void insertatend(int x);//x is the key element.
void print();
void insertatend(int x)
{
node *ptr;
ptr=(node*)malloc(sizeof(node));
ptr->info=x;
if(head==NULL)
{
ptr->next=ptr;
head=ptr;
}
else
ptr->next=ptr;
}
void print() //To print the list
{
node *temp=head;
printf("List is-");
while(temp!=NULL)
{
printf("%d",temp->info);
temp=temp->next;
}
}
Consider your insert method (I will take head as a parameter here instead of a global)
void insertatend(node **hd, int x) {
node *ptr = NULL, *cur = NULL;
if (!(ptr = malloc(sizeof (node)))) {
return;
}
if (!*hd) {
*hd = ptr;
} else {
cur = *hd;
while (cur->next) {
cur = cur->next;
}
cur->next = ptr;
}
}
You need to traverse your list from the end to its back in order to perform the insertion correctly. (Hence the while loop in the above function).
Your "temp != NULL" will never become false after the insertion, because in that insertion you set the next pointer to itself, thus creating a link loop.
it should be more like this:
void insertatend(int x)
{
node *ptr;
ptr=malloc(sizeof(node)); //don't cast pointers returned by malloc
ptr->info=x;
ptr->next=NULL; //set next node pointer to NULL to signify the end
if(head==NULL)
{
head=ptr;
}
else
{
node* tmp = head;
while(tmp->next) tmp = tmp->next; //get last node
tmp->next=ptr; //attach new node to last node
}
}
also your else branch was incorrect, creating another link loop.
You need to pass the last element of the list:
void insertatend(node *last, int x)
Or put a a tail node as global:
node *head = NULL;
node *tail = NULL;
void insertatend(int x)
{
node *ptr;
ptr = malloc(sizeof(node)); /* Don't cast malloc */
ptr->info = x;
ptr->next = NULL;
if (head == NULL) {
head = ptr;
} else {
tail->next = ptr;
}
tail = ptr;
}
You could also redefine your node struct to include next, prev, head, and tail pointers and manipulate them appropriately.
In your case, you should only need to set the head pointer on the tail node and the tail pointer on the head node. Set next and prev on all nodes. head pointer on head node should point to itself; tail pointer on tail node should point to itself. Head->prev = NULL; Tail->next = NULL;
Then just pass the head pointer always to your insertatend func.

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