segmentation fault in singly linked list - c

I am currently writing a program that implements a linked list to maintain a list on integers in sorted order. The program reads the integers from a file in the format of
d [\t] 7
i [\t] 8
i [\t] 7
i [\t] 10
with 'd' meaning delete from the list and 'i' inserting into the list, with no repeat integers allowed. This is the code I have so far:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data;
struct Node* next;
};
int delete(struct Node** head, int key){
if(head == NULL)
{
return -1;
}
struct Node* ptr = *head;
struct Node* prev = NULL;
while(ptr->data != key && ptr->next!=NULL)
{
prev = ptr;
ptr = ptr->next;
}
if(ptr->data == key)
{
if(prev)
{
prev->next = ptr->next;
}
else
{
*head = ptr->next;
}
free(ptr);
return key;
}
return -1;
}
int insert(struct Node** head, struct Node* newNode){
struct Node* ptr;
if(*head == NULL || (*head)->data >= newNode->data)
{
newNode->next = *head;
*head = newNode;
}
else
{
ptr = *head;
while(ptr->next != NULL && ptr->next->data < newNode->data)
{
ptr = ptr->next;
}
newNode->next = ptr->next;
ptr->next = newNode;
}
return 0;
}
int main(int argc, char* argv[]){
FILE *fp = fopen(argv[1], "r");
int num, found;
char c;
struct Node* head = NULL;
struct Node* ptr = head;
while(fscanf(fp, "%c\t%d\n", &c, &num)!=EOF)
{
for(ptr=head; ptr!=NULL; ptr=ptr->next)
{
if(ptr->data == num)
{
found = 1;
}
}
if(found != 1)
{
if(c == 'i')
{
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = num;
newNode->next = NULL;
insert(&head, newNode);
}
}
if(c == 'd')
delete(&head, num);
}
found = 0;
}
for(ptr=head; ptr!=NULL; ptr=ptr->next)
{
printf("%d ", ptr->data);
}
return 0;
}
It works fine when the first letter is 'i', but whenever the first letter is 'd' I get a segmentation fault. Why is this?

When you try to delete a node first thing you do, the list is empty and inside the delete function *head (notice the dereference!) is a null pointer.
Since *head is a null pointer, so will ptr be, and you then dereference ptr without checking for that.
You might want to modify the initial check to be head == NULL || *head == NULL.

whenever the first letter is 'd' I get a segmentation fault.
If the first letter is D, your list is still empty when you call delete.
In your first if, you need to dereference your pointer, as #SomeProgrammerDude mentionned.

Related

Stuck debugging a problem that I think is related to malloc

i'm currently writing a program that makes a sorted linked list in C. I'm new to C and am running into errors that I think are based around malloc. I would love if someone can give me some insight on my problems and how to fix them.
These are some of the errors I'm encountering:
==50002==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x563f6970912c bp 0x7ffe5d2b03f0 sp 0x7ffe5d2b03d0 T0)
==50002==The signal is caused by a WRITE memory access.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int data;
struct node* next;
};
void insert(struct node** n_ref, struct node* newNode) {
struct node* curr;
if (*n_ref == NULL || (*n_ref)->data >= newNode->data) {
newNode->next = *n_ref;
*n_ref = newNode;
} else {
curr = *n_ref;
while (curr->next != NULL && curr->next->data < newNode->data) {
curr = curr->next;
}
newNode->next = curr->next;
curr->next = newNode;
}
}
struct node* makeNode(int num){
struct node* newNode = NULL;
newNode->data = num;
newNode->next = NULL;
return newNode;
}
void delete(struct node** n, int num) {
struct node* temp = *n, *prev;
if (temp != NULL && temp->data == num) {
*n = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->data != num) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) {
return;
}
prev->next = temp->next;
free(temp);
}
void print(struct node* n) {
while (n != NULL) {
printf("%d ", n->data);
n = n->next;
}
}
int duplicate(struct node* n, int num) {
while (n != NULL) {
if (n->data == num) {
return 1;
}
n = n->next;
}
return 0;
}
int main(int argc, char* argv[argc + 1]) {
if (argc < 2) {
return EXIT_SUCCESS;
}
struct node* head = NULL;
FILE *file = fopen(argv[1], "r");
int x;
char str[10];
while (fscanf(file, "%s %d\n", str, &x) != EOF) {
if (strcmp(str, "INSERT")) {
if (duplicate(head, x) == 0) {
struct node* newNode;
newNode = (struct node*)malloc(sizeof(struct node));
newNode = makeNode(x);
insert(&head, newNode);
}
} else if (strcmp(str, "DELETE")) {
delete(&head, x);
}
print(head);
}
fclose(file);
return EXIT_SUCCESS;
}
Sorry for it being so messy. This is my first post here.
The original posted makeNode() assigns a local pointer to NULL and dereferences that 2x. Suggest allocating space and check the result, eg:
struct node* makeNode(int num) {
struct node* newNode;
newNode = malloc(sizeof(*newNode));
if (newNode) {
newNode->data = num;
newNode->next = NULL;
}
return newNode;
}

In my Singly linked List implementation why is it even though I allocated memory for the node to be freed, the pointer to the Node isn't NULL?

Using the delete_SLL function I want to delete the head of this singly linked list(head = 4). Although I get the correct output, the var struct Node* "temp" holding the value of the head isn't NULL. What is it about the variable "temp" that the free function not like? Is the node temp not Malloc-ed when setting it equal to the list head?
Source:Deleting a Node
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int item;
struct Node* next;
};
struct List{
struct Node* head;
struct Node* tail;
};
int SLL_empty(struct List* lst){
return lst->head == NULL ;
}
//newLst work
struct List newLst(){
struct List lst;
lst.head = NULL;
lst.tail = NULL;
return lst;
}
//Inserts a node to the front of the list[WORKS]
void insert_SLL(struct List* lst, int x){
struct Node* nde = (struct Node*)malloc(sizeof(struct Node));
nde->next = lst->head;
nde->item = x;
if (SLL_empty(lst))
lst->tail=nde;
lst->head = nde;
}
//Deletes a given Node
void delete_SLL(struct List* lst, int x){
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));;
temp = lst->head;
struct Node* prev = NULL;`enter code here`
//If the head has the key
if (temp != NULL && temp->item == x){
lst->head = temp->next;
temp->next = NULL;
free(temp);
}
// stops once the key is found
while(temp != NULL && temp->item != x){
prev = temp;
temp= temp->next;
}
//If not in list
if (temp == NULL) return;
//If middle
if (temp != NULL && temp->item == x){
prev->next = temp->next;
temp->next = NULL;
}
//if at the end
if (temp != NULL && temp->item == lst->tail->item){
lst->tail= prev;
prev->next = NULL;
}
free(temp);
}
int SLL_pop(struct List *list){
struct Node* nde = list->head;
int item = nde->item;
list->head = nde->next;
free(nde);
if (SLL_empty(list))
list->tail = NULL;
return item;
}
int main(int argc, const char * argv[]) {
int i;
struct List list = newLst();
for (i = 0; i < 5; ++i)
insert_SLL(&list, i);
// printf("The length of the linkedLst is: %d\n",SLL_length(&list));
delete_SLL(&list, 4);
while ( list.head != NULL )
printf("Node: %d\n", SLL_pop(&list));
return 0;
}
The main purpose of free() is to ask the OS take the allocated memory back to the system. You might not be able to "see" that but if you try to access any element at the "temp" afterward, you should get an error.
While the "temp" in the program is only a variable. C doesn't require to, and can't change the given pointer to NULL due to pass-by-value sense. It's the programmer's work to remember that this pointer is no longer valid.
Or you can set it to NULL manually each time you free a pointer.

Something wrong with strcmp?

My assignment is to read a file in to a linked list. The file contains a name and a letter indicating what to do with the name, either add or delete from list. The file is in this format:
Kathy a
Beverly a
Chuck a
Radell a
Gary a
Roger d
and so on...
The problem comes when i try to split up the name and the operation. The strcmp() doesn't even recognize the op_code variable in my code. I printed out both the name and the op_code and they print right unless i put a character near the op_code.
Here's my code:
//Tristan Shepherd
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char name[42];
struct node *next;
};
void printList(struct node *head)
{
struct node *current = head;
while (current)
{
printf("3 %s\n", current->name);
current = current->next;
}
}
void addFront(struct node **head, char *newname)
{
struct node* newnode = (struct node*)malloc(sizeof(struct node));
strcpy(newnode->name, newname);
newnode->next = (*head);
(*head) = newnode;
}
void delete(struct node **head, char *namedelete)
{
struct node* temp = *head, *prev;
if (temp != NULL && temp->name == namedelete)
{
*head = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->name != namedelete)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
free(temp);
}
void readfile(struct node *head)
{
FILE *file = fopen("hw8.data", "r");
char tname[42];
char *tempname = (char*)malloc(42*sizeof(char));
char *op_code = (char*)malloc(1*sizeof(char));
while(fgets(tname, sizeof(tname), file))
{
tempname = strtok(tname, " ");
op_code = strtok(NULL, "\n");
printf("%s\n", tempname);
printf("%s\n", op_code);
if (!strcmp(op_code, "a"))
{
addFront(&head, tempname);
}
else if (!strcmp(op_code, "d"))
{
delete(&head, tempname);
}
}
fclose(file);
printList(head);
}
int main()
{
struct node *head = NULL;
readfile(head);
exit(0);
}
The only issue I see with in readFile() is a memory leak.
char *tempname = (char*)malloc(42*sizeof(char));
char *op_code = (char*)malloc(1*sizeof(char));
should just be
char *tempname;
char *op_code;
strtok() breaks up the string in place, it does not produce a copy of the string, so no need to allocate extra memory.
I do see some issues in delete() however
You should be using strcmp() here instead of ==, like you do in readfile()
if (temp != NULL && temp->name == namedelete)
while (temp != NULL && temp->name != namedelete)
You may also need to initialize prev.
With your code as-is, add seemed to be working fine, and with my changes, delete looks ok.

c linked list delete smallest element [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Lists seem really hard for me. I want to find the smallest element in a file: 1 5 8 6 4 8 6 48 9. It's 1 and I want to delete that 1. I can find the smallest element but can not delete it. I find the smallest element place but not the value. I tried copying deleting function from the web, however I cant understand it due to the fact that I'm really new to C. It writes an error that dereferencing to incomplete type. Please help. Post whole code because it should be more convenient to understand.
#include <stdio.h>
#include <stdlib.h>
typedef struct linkedList {
int value;
struct linkedList *next;
} linkedList, head;
linkedList *readList(linkedList *head) {
FILE *dataFile;
dataFile = fopen("duom.txt", "r");
if (dataFile == NULL) {
printf("Nepasisekė atidaryti failo\n");
} else {
printf("Duomenų failą pavyko atidaryti\n");
}
while (!feof (dataFile))
if (head == NULL) {
head = malloc(sizeof(linkedList));
fscanf(dataFile, "%d", &head->value);
head->next = NULL;
} else {
struct linkedList *current = head;
struct linkedList *temp = malloc(sizeof(linkedList));
while (current->next != NULL) {
current = current->next;
}
fscanf(dataFile, "%d", &temp->value);
current->next = temp;
temp->next = NULL;
}
return head;
}
void search(linkedList *head, int *lowest) {
int a[100];
int i = 0;
int minimum;
int b = 0;
linkedList *current = head;
while (current != NULL) {
a[i] = current->value;
current = current->next;
i++;
}
b = i;
i = 0;
minimum = a[0];
while (b > 0) {
if (minimum > a[i]) {
minimum = a[i];
lowest = i;
}
i++;
b--;
}
}
void deleteNode(struct node **head_ref, int key) {
struct node* temp = *head_ref, *prev;
if (temp != NULL && temp->data == key) {
*head_ref = temp->next; // Changed head
free(temp); // free old head
return;
}
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
if (temp == NULL)
return;
prev->next = temp->next;
free(temp);
}
void printList(linkedList *head) {
linkedList *current = head;
while (current != NULL) {
printf("%d->", current->value);
current = current->next;
}
printf("NULL\n");
return;
}
int main() {
linkedList *A = NULL;
A = readList(A);
search(A);
head = head->next;
minimum = head->value;
headk->next = head->next;
free(head);
printList(A);
return 0;
}
like this
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct linkedList{
int value;
struct linkedList *next;
} linkedList, node;
linkedList *readList(void){
FILE *dataFile;
dataFile = fopen("duom.txt", "r");
if(dataFile == NULL) {
perror("file open");
return NULL;
}
int v;
node head = {0, NULL}, *curr = &head;
while (1 == fscanf(dataFile, "%d", &v)){
node *new_node = malloc(sizeof(node));
if(new_node == NULL){
perror("malloc");
break;
}
new_node->value = v;
new_node->next = NULL;
curr = curr->next = new_node;
}
fclose(dataFile);
return head.next;
}
int searchMin(linkedList *head){
if(head == NULL){
fprintf(stderr, "%s: The list MUST NOT be NULL.\n", __func__);
return INT_MIN;
}
int min = head->value;
node *p = head->next;
while(p){
if(p->value < min)
min = p->value;
p = p->next;
}
return min;
}
void deleteNode(node **head_ref, int key){
node *curr = *head_ref, *prev = NULL;
while (curr != NULL && curr->value != key){
prev = curr;
curr = curr->next;
}
if (curr == NULL) return;//not found
if(prev)
prev->next = curr->next;
else
*head_ref = curr->next;
free(curr);
}
void printList(linkedList *head){
node *current = head;
while (current != NULL) {
printf("%d->", current->value);
current = current -> next;
}
puts("NULL");
}
void freeList(linkedList *list){
while(list){
node *temp = list;
list = list->next;
free(temp);
}
}
int main(void){
linkedList *A = readList();
int min = searchMin(A);
printList(A);
deleteNode(&A, min);
printList(A);
freeList(A);
return 0;
}
Please try if this program can help you.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
struct node {
int data;
struct node *next;
};
void push(struct node **head_ref, int 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 deleteNode(struct node **head_ref, int key) {
struct node *temp = *head_ref, *prev;
if (temp != NULL && temp->data == key) {
*head_ref = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
free(temp);
}
void printList(struct node *node) {
while (node != NULL) {
printf(" %d ", node->data);
node = node->next;
}
}
void min(struct node **q) {
struct node *r;
int min = INT_MAX;;
r = *q;
while (r != NULL) {
if (r->data < min) {
min = r->data;
}
r = r->next;
}
printf("The min is %d", min);
deleteNode(q, min);
printf("\n");
}
int main() {
struct node *head = NULL;
FILE *file = fopen("duom.txt", "r");
int i = 0;
fscanf(file, "%d", &i);
while (!feof(file)) {
push(&head, i);
fscanf(file, "%d", &i);
}
fclose(file);
puts("Created Linked List: ");
printList(head);
min(&head);
puts("\nLinked List after Deletion of minimum: ");
printList(head);
return 0;
}
file duom.txt
1 5 8 6 4 8 6 48 9
Test
./a.out
Created Linked List:
9 48 6 8 4 6 8 5 1 The min is 1
Linked List after Deletion of minimum:
9 48 6 8 4 6 8 5 ⏎

C - Popping last item from linked lists

I am learning linked lists and they are causing me a lot of troubles.
I am calling the function with this call:
pop(&list);
ANd here's the code:
void pop(NODE** first) {
if(*first != NULL && first!= NULL){
NODE* ptr = *first;
while(ptr->next->next != NULL){
ptr = ptr->next;
}
free(ptr->next);
ptr->next = NULL;
}
It's also causing memory leak error even if I call it single time..
When calling this function multiple times, there are more memory leak errors.
Thanks in advance, Mimpopo.
EDIT: Definition of NODE
typedef struct node {
int data;
struct node *next;
} NODE;
The full CODE:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} NODE;
NODE* insert(NODE *first, int n){
// create new node
NODE* new = (NODE*)malloc(sizeof(NODE));
new->data = n;
new->next = NULL;
// if first is NULL, this will be the first
if(first == NULL)
return new;
// otherwise, place it correctly
NODE* ptr = first;
// check inserting at the begining
if(ptr->data > new->data){
new->next = ptr;
return new;
}
// insert in the middle
while(ptr->next != NULL){
if(ptr->next->data > n && ptr->data < n){
new->next = ptr->next;
ptr->next = new;
break;
}
ptr = ptr->next;
}
// insert at the end of list
if(ptr->next == NULL){
ptr->next = new;
}
return first;
}
void traverse(NODE *first){
NODE* ptr = first;
while(ptr != NULL){
printf("%d\n", ptr->data);
ptr = ptr->next;
}
}
NODE* search(NODE *first, int n){
NODE* ptr = first;
while(ptr != NULL){
if(ptr->data == n){
printf("FOUND %d\n!", n);
return ptr;
}
ptr = ptr->next;
}
}
int main(){
NODE* first = NULL;
NODE* this = NULL;
first = insert(first, 7);
first = insert(first, 10);
first = insert(first, 11);
first = insert(first, 1);
first = insert(first, 3);
first = insert(first, 5);
first = insert(first, 22);
first = insert(first, 23);
first = insert(first, 24);
first = insert(first, 125);
pop(&first);
}
I have not looked through all your code but as for the function then it can be written the following way
void pop( NODE ** first )
{
if ( *first != NULL )
{
NODE *prev = NULL;
NODE *current = *first;
while ( current->next )
{
prev = current;
current = current->next;
}
if ( prev != NULL ) prev->next = current->next;
else ( *first = NULL );
free( current );
}
}
As for your function implementation then it contains many errors. For example in this statement
if(*first != NULL && first!= NULL){
you shall swap the first and the second comparisons. That is the condition shall look like
if(first != NULL && *first!= NULL){
In this statement
while(ptr->next->next != NULL){
You have to be sure that ptr->nextis not equal to NULL.
Also you do not check whether the deleted node is the first node of the list.
Take into account that function insert is also wrong. You consider only one condition in this code snippet
while(ptr->next != NULL){
if(ptr->next->data > n && ptr->data < n){
new->next = ptr->next;
ptr->next = new;
break;
}
ptr = ptr->next;
}
However it can be that for example
ptr->next->data >= n && ptr->data < n
or
ptr->next->data > n && ptr->data <= n

Resources