Segfault creating doubly linked list - c

I am trying to read numbers from the text file and create a doubly linked list. I have a decent understanding of doubly linked lists work in theory but I am struggling with the application. I know I am probably trying to dereference a NULL pointer or pointing out of range. But, I can't seem to figure out where exactly.
It outputs the first number and then gives me a segfault somewhere at the if/else statements.
#include<stdio.h>
#include<stdlib.h>
struct node {
int val;
struct node *next;
struct node *prev;
};
struct list {
struct node *head;
struct node *tail;
};
int main()
{
struct node *temp = NULL;
struct list *l = NULL;
FILE *fileptr;
char filename[20], num[3];
printf("Enter filename: ");
scanf("%s", filename);
fileptr = fopen (filename, "r");
while(fscanf(fileptr, "%s", num) != EOF)
{
printf("Number is: %d\n", atoi(num));
temp = (struct node *) malloc(sizeof(struct node));
printf("HELLO 1\n");
temp->val = atoi(num);
printf("HELLO 2\n");
if(l->tail == NULL)
{
l->head = temp;
l->tail = temp;
}
else
{
l->tail->next = temp;
temp->prev = l->tail;
l->tail = temp;
}
}
return 0;
}

struct list *l = NULL; is wrong as you have not allocated any memory to l
You can either do
struct list *l = ( struct list *)malloc(sizeof(struct list));
l->head = NULL;
l->tail = NULL;
OR you can try
struct list l = {0}; and later use l.head or l.tail

Related

Why is this code not able to read contents from a file into a linked list?

I am unable to understand what the problem is as it isn't giving the correct output
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node*next;
};
void traversal(struct node*ptr){
while(ptr!=NULL){
printf("Element is: %d\n",ptr->data);
ptr=ptr->next;
}
}
void read(struct node*head){
FILE*file;
int val;
struct node*cur=(struct node*)malloc(sizeof(struct node));
head=cur=NULL;
file=fopen("list.txt","r");
while(fscanf(file,"%d",&val)!=EOF){
struct node*ptr=(struct node*)malloc(sizeof(struct node));
ptr->data=val;
ptr->next=NULL;
if(head==NULL){
head=cur=ptr;
}
else{
cur=cur->next=ptr;
}
}
fclose(file);
}
int main(){
struct node* head;
//Allocate memory for linked list nodes in heap
head=(struct node*)malloc(sizeof(struct node));
read(head);
traversal(head);
}
The contents of the file is
3
5
6
1
3
The output gives infinite number of lines with not the correct values
Without getting into the implementation of read(), head will remain the same since read() is not modifying it but a copy. You're also nullifying the allocated memory which result in memory leaks.
Since there is no point in allocating head outside read(), I suggest you define it inside to make things more clean, and then return it. Something of this sort:
struct node *read_file() {
FILE *file;
int val;
struct node *prv = NULL;
struct node *head = (struct node *)calloc(1, sizeof(struct node));;
if (head == NULL) {
return NULL;
}
file = fopen("list.txt", "r");
if (fscanf(file, "%d", &val) != EOF) {
head->data = val;
prv = head;
}
while(fscanf(file, "%d", &val) != EOF){
struct node *curr = (struct node *)calloc(1, sizeof(struct node));;
curr->data = val;
if (prv)
prv->next = curr;
prv = curr;
}
fclose(file);
return head;
}
int main(){
struct node *head = read_file();
traversal(head);
}
Don't forget to free the nodes at the end.

Print function messes up the linked list

#include <stdio.h>
#include <stdlib.h>
struct Node
{
int val;
struct Node *next;
};
struct List
{
struct Node *head;
struct Node *tail;
};
typedef struct List *List;
void Print(List temp)
{
struct Node* print = temp->head;
while(print->next!=NULL)
{
printf("%d ", print->next->val);
print->next = print->next->next;
}
printf("\n\n");
}
int main()
{
int i;
List Numbers;
Numbers = (struct List *) malloc(sizeof(struct List));
if (Numbers== NULL)
printf("Out of memory!\n");
Numbers->head = (struct Node *) malloc(sizeof(struct Node));
if (Numbers->head == NULL)
printf("Out of memory!\n");
Numbers->head->next = NULL;
Numbers->tail = Numbers->head;
printf("Enter 5 numbers:");
struct Node* temp = Numbers->head;
for(i=0;i<5;i++)
{
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
scanf("%d", &newnode->val);
newnode->next = NULL;
temp->next = newnode;
temp = newnode;
Numbers->tail = newnode;
}
Print(Numbers);
Print(Numbers);
return 0;
}
When I first print the list it prints out correctly but then the second time it prints nothing and program crashes. I dont know why the list is getting destroyed, even though I am using temp node to print it. Should I change the print function or the problem is something else ?
Your problem come from the line:
print->next = print->next->next;
This line change the pointer of head->next. When you run it the first time the pointer of head->next is changed to every node and at the end is set to NULL.
To fix it just change it to:
print = print->next;
Then you can print you linked list correctly without changing the original linked list.
You probably want to change print->next = print->next->next; to print = print->next;.

Swap nodes in a linked list without swapping data

how can i use pointers without copying the data?
I want to write a bubble sorting function, but I got stuck, and need some help how to swap node addresses instead of values.
I have a file with city names, and temperatures:
Las Vegas, 25
New York, 33
Chicago, 23
Houston, 39
and I need to sort it by the temperature, and write it to another file.
UPDATE:
Ok, now I think i understand the theoratical part:
// p is my node
// p-prev -> p -> p-next -> p-next-next
prev->next = p->next;
p->next = p->next->next;
prev->next->next = p;
This is what i need to do, to swap the nodes, but syntactically i couldnt make it work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char name[128];
int id;
struct node *next;
}*head;
void readFile() {
char fnamer[128] = "";
printf("\nEnter the file name to read (delimiter: ,): \n");
scanf("%s",&fnamer);
FILE *inf = fopen(fnamer, "r");
char buffer[1024];
memset(buffer, 0, 1024);
while(fgets(buffer, 1024, inf)){
struct node *temp = malloc(sizeof(struct node));
temp->next = NULL;
if(sscanf(buffer, "%19[^,], %d", temp->name, &temp->id) != 2){
free(temp);
break;
}
if(!head){
head = temp;
} else{
temp->next = head;
head = temp;
}
}
fclose(inf);
}
int main(void) {
// Read a linked list from file
readFile();
//Bubble sort in linked list
struct node *loop1 = head;
while(loop1){
struct node *loop2 = loop1->next;
while(loop2){
if(loop1->id > loop2->id){
// Swap next pointers
// This is not working
struct node *temp = loop1->next;
loop1->next = loop2->next;
loop2->next = temp;
}
loop2 = loop2->next;
}
loop1 = loop1->next;
}
// Print the sorted linked list to file:
char foutname[100]="";
printf("\nPlease Enter the file name to write the result: \n");
scanf("%s",&foutname);
FILE *outf;
outf = fopen(foutname, "w+");
loop1 = head;
while(loop1){
printf("%s %d\n", loop1->name, loop1->id);
fprintf(outf, "%s %d\n", loop1->name, loop1->id);
loop1 = loop1->next;
}
fclose(outf);
return 0;
}
To swap two nodes in a singly-linked list you can use the following function
void swap(struct node **current)
{
struct node *tmp = (*current)->next->next;
(*current)->next->next = *current;
*current = (*current)->next;
(*current)->next->next = tmp;
}
For example to swap the head node and the next node you can call the function like
swap( &head );
See also my answer at this reference Bubble sort in c linked list where there is shown how to write the bubble sort algorithm for a singly-linked list.
We need to swap the next links such that the link chain is rearranged. If you swap node1 and node2, the link chain should change as follows:
//change the link chain from
node0 -> node1 -> node2 -> node3
//to
node0 -> node2 -> node1 -> node3
We put this inside a while loop and the loop breaks when there are no more swaps. We can improve this function by limiting the number comparisons. After each loop, the last element should be sorted.
To put this together,lets use typedef keyword so that we don't have to repeat struct everywhere.
typedef struct node_t
{
char name[20];
int id;
struct node_t *next;
} node;
void bubblesort(node **list)
{
if(!(*list)) return;
node *previous_node = NULL;
node *sort_up_to = NULL;
while(1)
{
previous_node = NULL;
node *ptr = *list;
node *last_change = NULL;
while(ptr->next)
{
//the rest of the list is sorted?
if(sort_up_to && ptr == sort_up_to) break;
node *next = ptr->next;
if(ptr->id > next->id)
{
if(previous_node == NULL)
*list = next;
else
previous_node->next = next;
ptr->next = next->next;
next->next = ptr;
last_change = next;
}
previous_node = ptr;
ptr = next;
}
//list is all sorted?
if(!last_change) break;
sort_up_to = last_change;
}
}
int main(void)
{
node* head = NULL;
FILE *fin = fopen("test.txt", "r");
if(!fin)
return 0;
node temp;
while(fscanf(fin, "%19[^,], %d\n", temp.name, &temp.id) == 2)
{
node *n = malloc(sizeof(node));
n->next = NULL;
strcpy(n->name, temp.name);
n->id = temp.id;
if(head)
n->next = head;
head = n;
}
fclose(fin);
bubblesort(&head);
for(node* n = head; n != NULL; n = n->next)
printf("%s %d\n", n->name, n->id);
return 0;
}

Create a new node for each entry in a .txt file

Okay so I've been doing a program which would read elements of a txt file using scanf (cmd input redirection). A new node must be created for every entry in the file and add it at the end of the list. Here's my code so far:
struct Elem{
int Atnum;
char Na[31];
char Sym[4];
};
struct nodeTag {
struct Elem entry;
struct nodeTag *pNext; // pointer to the next node
};
typedef struct nodeTag Node;
The function that would initialize it is this:
Node *
InitializeList(Node *pFirst, int n)
{
int i;
Node *head, *temp = 0;
pFirst = 0;
for (i=0; i<n; i++){
head = (Node *)malloc(sizeof(Node));
scanf("%d", &head->entry.AtNum);
scanf("%s", head->entry.Na);
scanf("%s", head->entry.Sym);
if (pFirst != 0)
{
temp->pNext = head;
temp = head;
}
else
{
pFirst = temp = head;
}
fflush(stdin);
temp->pNext = 0;
}
return pFirst;
}
and lastly, print it
void
Print( Node *pFirst )
{
Node *temp;
temp = pFirst;
printf("\n status of the linked list is\n");
while (temp != 0)
{
printf("%d %s %s", temp->entry.AtNum, temp->entry.Na, temp->entry.Sym);
temp = temp -> pNext;
}
}
Now, I can't get the program to run properly. No run-time errors though but the output seems to be garbage. I've been working for hours for this and I cant' get my head around it. Thank you for your help!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Elem
{
int AtNum;
char Na[31];
char Sym[4];
};
struct nodeTag
{
/* entry must be a pointer in order to not lose the values
and/or encounter memory conflicting errors
*/
struct Elem *entry;
struct nodeTag *pNext;
};
typedef struct nodeTag Node;
// insert node at the first location
Node *insertFirst(Node *head, struct Elem *data)
{
Node *node = (Node *) malloc(sizeof(Node));
// fill in data
node->entry = data;
/* point it to old first node
in simple words: "put this node before the head"
*/
node->pNext = head;
// point first to new first node
head = node;
return head;
}
Node *InitializeList(int n)
{
int i;
Node *head = NULL;
struct Elem *data;
for (i = 0; i < n; i++)
{
// allocate memory for the struct Elem of each node
data = (struct Elem*) malloc(sizeof(struct Elem));
scanf("%d", &data->AtNum);
scanf("%s", data->Na);
scanf("%s", data->Sym);
head = insertFirst(head, data);
}
return head;
}
//display the list
void printList(Node *head)
{
Node *ptr = head;
printf("\nStatus of the linked list is:\n");
//start from the beginning
while(ptr != NULL)
{
printf("%d %s %s", ptr->entry->AtNum, ptr->entry->Na, ptr->entry->Sym);
printf("\n");
ptr = ptr->pNext;
}
}
int main(int argc, char *argv[])
{
Node *head;
head = InitializeList(3);
printList(head);
return 0;
}
I hope I didn't come too late! If not, please check this answer as the solution, thanks! :-)

C list->data doesnt show on terminal

The console doesnt show the data from my list node.I filled it with chars that i took from a text File.
#include<stdio.h>
#include<stdlib.h>
struct list_node{
char data;
struct list_node* next;
};
typedef struct list_node* node;
node insert_right(node list,char data)
{
node new_node = (node) malloc(sizeof(struct list_node));
new_node->data = data;
new_node->next = list->next;
list->next = new_node;
return new_node;
}
int main()
{
FILE *fr = fopen("dat1.txt","r");
node list = (node) malloc(sizeof(struct list_node));
int i;
while((i = fgetc(fr)) != EOF){
insert_right(list,i);
}
printf("%c",list->data);
}
The main problem i think would be in the insert method.
You are creating a linked list. Each node you create needs to point to either NULL or the next node. You were not quite making the links. Also you were not getting the new_node you you were returning. Also when printing out a list you have to go through each node (like an array).
#include<stdio.h>
#include<stdlib.h>
struct list_node{
char data;
struct list_node* next;
};
typedef struct list_node* node;
node insert_right(node list,char data)
{
node new_node = (node) malloc(sizeof(struct list_node));
new_node->data = data;
list->next = new_node;
new_node->next = NULL;
return new_node;
}
int main()
{
FILE *fr = fopen("dat1.txt","r");
node list = (node) malloc(sizeof(struct list_node));
int i;
node next = list;
while((i = fgetc(fr)) != EOF){
next = insert_right(next,i);
}
node print = list;
while(print != NULL){
printf("%c",print->data);
print = print->next;
}
}
You are allocating memory to a node called list, but yet you do not initialize any value for data, it can be garbage or any character that does not show up in the console.
When you insert a new value, a new node is created and the first one, the "head" so to speak, is still uninitialized even though it is pointing to a second node that has a meaningful data there.
This is your list:
// Node Y (X) indicates the Y-th node that has a X value.
Node1 (garbage) -> Node2 (value) -> Node3 (value) -> garbage
The last node of your list (which is also the first when you create it) should be pointing to NULL instead of being uninitialized.
I am also pretty sure that your list is poor-implemented because the new elements are always being pointed by list, so you lose track of the ones you created before.
Here is a better version, in my opinion:
#include<stdio.h>
#include<stdlib.h>
struct list_node{
char data;
struct list_node* next;
};
typedef struct list_node* node;
void insert_right(node list,char data)
{
node new_node = (node) malloc(sizeof(struct list_node));
node temp = list;
// It runs through the list until it reaches the last node
while(temp->next != NULL) temp = temp->next;
temp->data = data;
temp->next = new_node;
new_node->next = NULL;
}
int main()
{
FILE *fr = fopen("dat1.txt","r");
// List points to only the first element of the list.
node list = (node) malloc(sizeof(struct list_node));
list->next = NULL;
int i;
while((i = fgetc(fr)) != EOF){
insert_right(list,i);
}
while(list != NULL) {
printf("%c",list->data);
list = list->next;
}
}
#include <stdio.h>
#include <stdlib.h>
struct list_node {
char data;
struct list_node* next;
};
int main()
{
FILE *fr = fopen("dat1.txt","r");
struct list_node *list = malloc(sizeof(*list)), *pos = list;
int i;
while ((i = fgetc(fr)) != EOF) {
pos->data = i;
pos->next = malloc(sizeof(*list->next));
pos = pos->next;
}
pos->next = NULL;
while (list->next) {
printf("%c ", list->data);
free(list); /* important!!!! */
list = list->next;
}
putchar('\n');
return 0;
}

Resources