LinkedList functions crash in c - c

I implemented a linked list in c. when i test it, whenever i reach display function or insert at the end the program crashes. These are the functions:
struct Node
{
char data;
struct Node *next;
};
struct LinkedList
{
struct Node *head;
};
void insertAtBeginning(struct LinkedList *LL, char ele)
{
struct Node *new = (struct Node*)malloc(sizeof(struct Node));
new->data = ele;
new->next = NULL;
if(new->data == '\n')return;
if(LL->head==NULL)LL->head = new;
else
{
new->next=LL->head;
LL->head=new;
}
}
void insertAtTheEnd(struct LinkedList *LL, char ele)
{
struct Node *new = (struct Node*) malloc(sizeof(struct Node));
new->data = ele;
new->next = NULL;
if(LL->head==NULL){LL->head=new;return;}
struct Node *current = LL->head;
while(current->next != NULL) {current = current->next;}
current->next = new;
}
void deleteNode(struct LinkedList* LL, char ele)
{
struct Node *current = LL->head;
struct Node *temp = LL->head;
while(current->next->data!=ele && current!=NULL)current=current->next;
temp=current->next;
current->next=current->next->next;
free(temp);
}
void deleteFirstNode(struct LinkedList* LL)
{
struct Node *temp;
if(LL->head != NULL)
{
temp = LL->head;
LL->head = LL->head->next;
free(temp);
}
}
void displayLinkedList(struct LinkedList LL)
{
struct Node *current = LL.head;
printf("List: ");
while(current != NULL)
{
printf("%c",current->data);
current = current->next;
}
printf("\n");
}
This is the main:
main()
{
struct LinkedList LL;
char c = '0';
//Inserting at beginning
printf("Type a string. Press Enter to end: ");
while(c != '\n')
{
scanf("%c",&c);
insertAtBeginning(&LL, c);
}
printf("List: ");
displayLinkedList(LL);
printf("\n");
//Inserting at end
c='0';
printf("Type a string. Press Enter to end: ");
while(c != '\n')
{
scanf("%c",&c);
insertAtTheEnd(&LL, c);
}
printf("List: ");
displayLinkedList(LL);
printf("\n");
//Remove
printf("Enter a char to remove: ");
scanf("%c",&c);
deleteNode(&LL, c);
printf("\n");
printf("List: ");
displayLinkedList(LL);
printf("\n");
deleteFirstNode(&LL);
printf("List: ");
displayLinkedList(LL);
}
of course This is done after inserting the necessary libraries.

you have to set NULL to next when you create element. if you do not do it, your while loop behaviour will be buggy
void insertAtTheEnd(struct LinkedList *LL, char ele)
{
struct Node *new = (struct Node*) malloc(sizeof(struct Node));
new->next = NULL;
new->data = ele;
if(LL->head == NULL) LL->head = new;
else
{
struct Node *current = LL->head;
while(current->next != NULL) {current = current->next;}
current->next = new;
}
}
, and do same for other functions.
also you have to set NULL to your LinkedList.head. so, set NULL when you define LinkedList
struct LinkedList LL;
LL.head = NULL;

i asume the line if(current = LL->head) is wrong
bacause temp = current->next would crash if the result is NULL
otherwise the code after the if statement doesnt makes sense

There are some instances where you will try to insert at the end. When you have something of the form node_new->next->prev = node, you must check to make sure that node_new->next is not NULL, because NULL does not have any type and thus does not have a prev field.
You may also consider making all of your functions return int, so that you can know if and what goes wrong.

Related

Segmentation fault in linked list program (c language)

I'm trying to write a code for linked lists using c++. Insert at begin and Insert at end are not working for some reason. Here is the code.
`
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
void insertAtBeginning(int );
void insertAtEnd(int );
void printLL();
struct Node
{
int data;
struct Node *link;
};
struct Node *head;
int main()
{
struct Node *temp, *newnode;
int ch=1, i=1, info;
head = NULL;
while(ch)
{
printf("Enter data: ");
scanf("%d", &info);
newnode = (struct Node *)malloc(sizeof(struct Node));
newnode->data = info;
newnode->link = NULL;
if(head == NULL)
{
head = newnode;
temp = newnode;
}
else
{
temp ->link = newnode;
temp = newnode;
}
printf("You wish to continue? (press 0 to terminate)\n");
scanf("%d",&ch);
if(!ch)
{
break;
}
}
temp = head;
while(temp!=NULL)
{
printf("%d -> ",temp->data);
temp = temp->link;
}
printf("\n");
insertAtBeginning(50);
insertAtEnd(150);
//printLL();
}
void insertAtBeginning(int info)
{
struct Node *newnode;
newnode->data = info;
printf("\n%d\n", newnode ->data);
newnode->link = head;
head = newnode;
}
void insertAtEnd(int info)
{
struct Node *temp, *newnode;
newnode->link = NULL;
newnode->data = info;
temp = head;
while(temp!=NULL)
{
temp = temp->link;
}
temp->link = newnode;
printf("\n%d\n", newnode -> data);
}
void printLL()
{
struct Node *temp;
temp = head;
while(temp!=NULL)
{
printf("%d -> ",temp->data);
temp = temp->link;
}
}
`
The problem is somewhere around newnode->data = info in the functions.
I created two functions, one to insert an element at beginning and one to insert an element at end. In both of them, i've created a newnode. The problem is I cannot insert data into those nodes.
When you want to append a new node to the end of a linked list, you must find your last node (a node which its link is NULL, not itself). Also, it is better to use meaningful variable name (temp is too general name). You also forgot to malloc new nodes in insertAtBeginning and insertAtEnd functions. I've fixed these issues in the following code
#include<stdio.h>
#include<stdlib.h>
void insertAtBeginning(int );
void insertAtEnd(int );
void printLL();
struct Node
{
int data;
struct Node *link;
};
struct Node *head = NULL;
int main()
{
struct Node *it, *newnode, *tail;
int ch=1, i=1, info;
while(ch){
printf("Enter data: ");
scanf("%d", &info);
newnode = malloc(sizeof(struct Node));
newnode->data = info;
newnode->link = NULL;
if (head == NULL) {
head = newnode;
tail = newnode;
} else {
tail->link = newnode;
tail = newnode;
}
printf("You wish to continue? (press 0 to terminate, else to continue)\n");
scanf("%d",&ch);
if(ch == 0) {
break;
}
}
it = head;
while(it != NULL) {
printf("%d -> ",it->data);
it = it->link;
}
printf("\n");
insertAtBeginning(50);
insertAtEnd(150);
}
void insertAtBeginning(int info)
{
struct Node *newnode;
newnode = malloc(sizeof(struct Node));
newnode->data = info;
printf("\n%d\n", newnode->data);
newnode->link = head;
head = newnode;
}
void insertAtEnd(int info)
{
struct Node *it, *newnode;
newnode = malloc(sizeof(struct Node));
newnode->link = NULL;
newnode->data = info;
it = head;
while(it->link != NULL)
{
it = it->link;
}
it->link = newnode;
printf("\n%d\n", newnode->data);
}
void printLL()
{
struct Node *it;
it = head;
while(it!=NULL)
{
printf("%d -> ",it->data);
it = it->link;
}
}
You're treating your uninitialized stack variable (struct Node *newnode) as a pointer to a struct Node and trying to update its fields:
struct Node *newnode;
newnode->data = info;
This doesn't work because the value of newnode is whatever garbage was on the stack beforehand, and trying to deref it (*newnode) will likely give a seg fault since you're trying to read from some unknown memory address.
Notice how inside main, you assign a result from malloc to newnode, this means you know that (given that malloc didn't return NULL), the pointer is valid, and you're free to use the memory it points to.

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.

Segfault while printing linked list after stack clear

To be more specific, this code is supposed to be a lesser clone of the Unix function dc. The linked list seems to be working fine. If I attempt to use c to clear the memory, add more numbers, then print again with f I get a segfault. It seems to be printing what should be the Null Node in the linked list.
Interaction:
$ ./test
1 2 3
f
3
2
1
c
4 5
f
5
4
0
Segmentation Fault
Here's the code itself:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int val;
struct Node *next;
};
void cons_node(struct Node **head, int num)
{
struct Node *newNode = malloc(sizeof(struct Node));
newNode->val = num;
newNode->next = NULL;
if (*head == NULL){
*head = newNode;
}
else {
newNode->next = *head;
*head = newNode;
}
}
I'm assuming the problem lies here in the display func:
void display_list(struct Node *head)
{
struct Node *current = head;
while(current != NULL)
{
printf("%d\n", current->val);
current = current->next;}
}
void print_top(struct Node *head)
{
printf("%d\n", head->val);
}
or here in the clear func:
void clear_stack(struct Node *head)
{
struct Node *current;
while ((current = head)!= NULL) {
head = head->next;
free(current);
}
}
void vorpal_func(struct Node *head)
{
struct Node *current;
current = head;
free(current);
}
int main(){
int input;
int first = 1;
char quit = 'n';
char inputchar = ' ';
struct Node *head = NULL;
while (quit == 'n'){
if (scanf("%d", &input) == 1){
cons_node(&head, input);
first = 0;
}
else{
inputchar = getchar();
if(first == 1)
printf("List is empty\n");
else{
switch (inputchar){
case 'q':
quit = 'y';
break;
case 'E':
quit = 'y';
break;
case 'f':
display_list(head);
break;
case 'p':
print_top(head);
break;
case 'c':
clear_stack(head);
first = 1;
break;
case 't':
vorpal_func(head);
break;
}
}
}
}
return 0;
}
I've been attempting to figure out the problem for a few hours now. Any tips?
You don't clear your head after calling clear_stack, so when you add your next node, the next pointer is set to something that points into memory that has been freed. Or you could pass a pointer to head to clear_stack if you preferred.
void clear_stack(struct Node **head)
{
while (*head != NULL)
{
Node *current = *head;
*head = current->next;
free(current);
}
}
In passing, cons_node could be written like this
void cons_node(struct Node **head, int num)
{
struct Node *newNode = malloc(sizeof(struct Node));
newNode->val = num;
newNode->next = *head;
*head = newNode;
}

Linked lists, how to insert if head does not exist?

I got a linked list, which should save the Outcome (W or L) and the gained/lost points for each match. All good so far, but I'm getting trouble when the head does not exist/is empty. I also realized I have a pretty bad overview of how to implement linked lists, anyone got good and understandable resources? Anyway this is my code:
#include <stdio.h>
#include <stdlib.h>
struct node {
int point;
char outcome;
struct node *next;
};
void add(struct node *data){
if(data == NULL){
data = malloc(sizeof(struct node));
printf("Outcome and points?\n");
int point;
char outcome;
scanf("%c %d",&outcome,&point);
fgetc(stdin);
data->point=point;
data->outcome=outcome;
data->next=NULL;
}else{
struct node *current= data;
while(current->next != NULL){
current = current->next;
}
current->next = malloc(sizeof(struct node));
current=current->next;
printf("Outcome and points?\n");
int point;
char outcome;
scanf("%c %d",&outcome,&point);
fgetc(stdin);
current->point=point;
current->outcome=outcome;
current->next=NULL;
}
}
void print(struct node *data){
struct node *current = data;
while(current != NULL){
printf("%c with %3d\n",current->outcome,current->point);
current = current->next;
}
}
int main()
{
struct node *head=NULL;
add(head);
add(head);
add(head);
print(head);
}
Any help would be appreciated :)
When you execute:
void add(struct node *data){
if(data == NULL){
data = malloc(sizeof(struct node));
the value of head does not change in the calling function.
Suggest a change of strategy.
struct node* add(struct node *head)
{
if(head == NULL){
head = malloc(sizeof(struct node));
printf("Outcome and points?\n");
int point;
char outcome;
scanf("%c %d",&outcome,&point);
fgetc(stdin);
head->point=point;
head->outcome=outcome;
head->next=NULL;
}else{
struct node *current= head;
while(current->next != NULL){
current = current->next;
}
current->next = malloc(sizeof(struct node));
current=current->next;
printf("Outcome and points?\n");
int point;
char outcome;
scanf("%c %d",&outcome,&point);
fgetc(stdin);
current->point=point;
current->outcome=outcome;
current->next=NULL;
}
return head;
}
And, then change the usage:
int main()
{
struct node *head = add(NULL);
add(head);
add(head);
print(head);
}
You can simplify the code by starting the list with an anchor node. An anchor node is a node that is only used for its next pointer. In the code below, the call to calloc creates the anchor node, and sets all of the fields in the anchor to 0. In other words, a node is created with next == NULL.
Note that when printing the list, the for loop starts by skipping the anchor node with for (list = list->next;...)
#include <stdio.h>
#include <stdlib.h>
struct node
{
int point;
char outcome;
struct node *next;
};
void add( struct node *list )
{
struct node *data;
data = malloc(sizeof(struct node));
data->next = NULL;
printf("Outcome and points?\n");
scanf("%c %d",&data->outcome,&data->point);
fgetc(stdin);
while (list->next != NULL)
list = list->next;
list->next = data;
}
void print( struct node *list )
{
for (list = list->next; list != NULL; list = list->next)
printf("%c with %3d\n", list->outcome, list->point);
}
int main()
{
struct node *head = calloc( 1, sizeof(struct node) );
add(head);
add(head);
add(head);
print(head);
}
Side note: I've omitted some error checking to keep things simple, you should really be checking the return values from calloc, malloc, and scanf and handle any errors. And, of course, you should free all of the nodes at the end.

inserting an element in a linked list

Considering a linked list containing five elements.
1,2,3,4,5 a no '7' is to be inserted after two. we will have an head pointing to the first element of the linked list and ptr at the last. while inserting an element before 3 we will loop through the linked list starting from head to last and we will introduce another pointer(prev) to hold the previous pointers address.ptr will point to the current node and if a matching data is found(3) then we have to include the new node between 2 and 3.
We can do it as we have previous pointer.How to do it without using a previous pointer.
EDITED:
#include<stdio.h>
#include<stdlib.h>
struct list
{
int data;
struct list* link;
};
struct list *head=NULL;
struct list *tail=NULL;
void createList(int value);
void displayList(struct list* head_node);
void insertNewNode();
int value;
int main()
{
int i;
for(i=0;i<5;i++)
{
printf("\nEnter the data to be added into the list:\n");
scanf("%d",&value);
createList(value);
}
printf("\nCreated Linked list is\n");
//displayList(head);
printf("\nInsert a node\n");
insertNewNode();
displayList(head);
return 0;
}
void insertNewNode()
{
int val;
struct list* ptr=NULL,*new_node,*prev=NULL;
new_node = (struct list*)malloc(sizeof(struct list));
printf("Enter the data to be inserted!");
scanf("%d",&val);
for(ptr=head;ptr;ptr=ptr->link)
{
if(ptr->data == 3)
{
printf("Found");
new_node->data = val;
prev->link=new_node;
new_node->link = ptr;
}
prev = ptr;
}
}
void createList(int value)
{
struct list *newNode;
newNode = (struct list*)malloc(sizeof(struct list));
//tail = (struct list*)malloc(sizeof(struct list));
newNode->data = value;
if(head == NULL)
{
head = newNode;
}
else
{
tail->link = newNode;
}
tail = newNode;
tail->link = NULL;
}
void displayList(struct list *head_node)
{
struct list *i;
for(i=head;i;i=i->link)
{
printf("%d",i->data);
printf(" ");
}
printf("\n");
}
void insertNewNode()
{
int val;
struct list* ptr=NULL,*new_node;
new_node = (struct list*)malloc(sizeof(struct list));
printf("Enter the data to be inserted!");
scanf("%d",&val);
for(ptr=head;ptr;ptr=ptr->link)
{
if(ptr->data == 2)
{
printf("Found");
new_node->data = val;
new_node->link = ptr->link;
ptr->link = new_node;
}
}
}
Update:
This is probably what you want:
void insertNewNode()
{
int val;
struct list* ptr=NULL,*new_node;
new_node = (struct list*)malloc(sizeof(struct list));
printf("Enter the data to be inserted!");
scanf("%d",&val);
for(ptr=head;ptr->link;ptr=ptr->link)
{
if(ptr->link->data == 3)
{
printf("Found");
new_node->data = val;
new_node->link = ptr->link;
ptr->link = new_node;
}
}
}
Here:
if(ptr->link->data == 3)
you simply look ahead to check if next node has value that you need.
Let's call curr the pointer at the current element, next the pointer at the next element, and value the number stored.
Traverse the list until curr.value == 2, now just create a new_node with new_node.value = 7 and set new_node.next = curr.next and curr.next = new_node

Resources