Linked List program isn't updating properly - c

I have created a program that reads in a text file containing integers. It should read these integers in and then create a linked list of them. However, the head pointer of my program continually updates even when just the tail should be. Does anyone know why this is? The input file can be integers separated by spaces or newlines. Here is my code:
#include<stdlib.h>
#include<stdio.h>
#include <string.h>
/*THIS IS THE BASIC NAME STRUCTURE. IT CONTAINS A FIRST AND LAST NAME VARIABLE*/
struct number {
int * number; //number
};
/*THIS IS THE BASIC NAME NODE STRUCTURE. IT CONTAINS A NAME STRUCT AS WELL AS STRUCT NAMENODES TO PREVIOUS AND NEXT NODES*/
struct numberNode {
struct number number; //name stuct call
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
/*THESE NAMENODES WILL BE USED THROUGHOUT THE PRGRAM AS THE HEAD AND TAIL OF THE PROGRAM*/
struct numberNode *pHead = NULL, *pTail=NULL;
/*THIS PROGRAM READS A FILE AND PLACES THE NAMES INTO LINKED LIST*/
void insert_end(int *num)
{
struct numberNode *var = NULL,*temp = NULL; //set temp nodes
var=(struct numberNode *)malloc(sizeof(struct numberNode)); //allocate memory for new node
var->number.number= num; //set number of number stored in node
if(pHead==NULL){ //check if it is the head
pHead=var; //set node to head b/c of first element
pHead->pPrev=NULL; //set node next and prev to null
pHead->pNext=NULL;
pTail=pHead; //make head and tail the same
}else{
pTail=pHead; //set tail to head
while(pTail!=NULL) //while tail is not NULL
{
temp=pTail; //set temp node to tail pointer
pTail=pTail->pNext; //traverse the linked list
}
pTail=var; //set ptail to correct node
temp->pNext=pTail; //set the temps next to tail
pTail->pPrev=temp; //set the tail's previous pointer to temp
pTail->pNext=NULL; //set tail next to NULL
}
}
/*FUNCTION FOR DISPLAYING LINKED LIST DATA*/
void display(){
struct numberNode *node;
node=pHead;
printf("Displaying Linked List \n ************************************** \n");
while(node != NULL){
printf("Number is %d\n", *node->number.number);
node = node->pNext;
}
printf("List is terminated\n ************************************* \n");
}
void displayBackwards(){
struct numberNode *node;
node=pTail;
printf("Displaying Linked List Backwards \n ************************************** \n");
while(node != NULL){
printf("Number is %d\n", *node->number.number);
node = node->pPrev;
}
printf("List is terminated\n ************************************* \n");
}
/*DELETE NODE PASSED IN ARGUEMENT*/
void deleteNode(struct numberNode *node){
if (node!= pHead){
node->pPrev->pNext=node->pNext;
node->pNext->pPrev=node->pPrev;
node->pNext = NULL;
free(node);
}else{
pHead->pNext = pHead;
free(node);
}
}
//SWITCH THE LOCATIONS OF THE TWO NODES PASSED AS ARGUEMENTS
void switchNodes(struct numberNode *leftNode, struct numberNode *rightNode){
struct numberNode temp;
temp = *leftNode;
leftNode->number=rightNode->number;
rightNode->number= temp.number;
}
/*ORGANIZE LINKED LIST IN ALPHABETICAL ORDER*/
void organizeInAscendingOrder(){
struct numberNode *node = pHead;
int length=0;
while(node != NULL){
node = node->pNext;
length ++;
}
node = pHead;
int index = 0, secondIndex = 0;
for (index=0; index<length; index++){
for (secondIndex=0; secondIndex<length-1; secondIndex++){
if(node->number.number > node->pNext->number.number){
switchNodes(node, node->pNext);
}
node=node->pNext;
}
node=pHead;
}
}
/*PUSH NODE PASSED AS ARGUEMENT TO THE BACK*/
void pushToBack(struct numberNode *node){
pTail->pNext = node;
deleteNode(node);
}
int main() {
char file[100];
printf("Enter input file ");
scanf("%s", file);
FILE *in_file = fopen(file, "r");
int number;
char *buffer;
while(fscanf(in_file,"%d", &number)!=EOF)
{
insert_end(&number);
}
display();
organizeInAscendingOrder();
display();
displayBackwards();
}

as Paul said you don't necessarily need both struct, but the real problem is that when you read an int from the file you store in the variable "int number;" and each time you call the function insert_end(&number); you send the address of the variable number but in your insert_end function you assign the value of your new number in your new node to the address of number :
var->number.number= num;. So in your list all your number element in your numberNode will point the the same address.
a quick fix would be to allocate new memory space for each integer read in the file.
ex:
int* number = (int*)malloc(sizeof(int));
while(fscanf(in_file,"%d", number)!=EOF)
{
insert_end(number);
number = (int*)malloc(sizeof(int));
}
you could also remove pointers from the struct as suggested by Paul :
struct numberNode {
int number; //number
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
hope it helps,
[EDIT] : +1 for fhsilva who propose a better way to manage the tail, the head should always refere to the first element of the list and the tail should always point to the last one. This ways you don't new to go through the list to insert at the end becaus you already have a reference to the last element.(I couldn't comment on fhsilva's answer because I just subscribed to SO and don't have enough reputation...)
James

You are in a bit of a muddle with your data structures - you can just reduce this:
struct number {
int * number; //number
};
/*THIS IS THE BASIC NAME NODE STRUCTURE. IT CONTAINS A NAME STRUCT AS WELL AS STRUCT NAMENODES TO PREVIOUS AND NEXT NODES*/
struct numberNode {
struct number number; //name stuct call
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
to this:
struct numberNode {
int number; //number
struct numberNode *pNext; //pointer to next node
struct numberNode *pPrev; //pointer to previous node
};
i.e. you don't need more than one struct for this.

Not sure why you are traversing the list since it is double linked.
This should work:
if (pHead==NULL){
(...)
} else {
pHead->pPrev = var;
pTail->pNext = var;
var->pPrev = pTail;
var->pNext = pPrev;
pTail = var;
}

Related

I try to write code for linked lists in C

I must write a code for a lab and i don't understand how i can insert the nodes with which function.
struct list
{int value;
struct list * next;};
int main()........
the code says that we ask the user how many integers (N) he wants to insert to the list.. so easy printf, scanf
AND THEN ..It will ask for the numbers and list them in the order they are given.
I think that i need a for loop
but i know many function for inserting for example insertAfter, push etc, etc
I need you help! Thank you
The structure you have given represents a node. You first create a head of the list, then you need to read numbers one by one, create a node for each number and append it at the end of the list using append() function defined in the code given below.
Here is the full program you require (function codes taken from geeksforgeeks.org):
#include <stdio.h>
#include <stdlib.h>
// A linked list node
struct Node
{
int data;
struct Node *next;
};
/* Given a reference (pointer to pointer) to the head
of a list and an int, appends a new node at the end */
void append(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
// This function prints contents of linked list starting from head
void printList(struct Node *node)
{
while (node != NULL)
{
printf(" %d ", node->data);
node = node->next;
}
}
int main()
{
/* Start with the empty list */
struct Node* head = NULL;
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) {
int e;
scanf("%d", &e);
append(&head, e);
}
printList(head);
}

How to change sinlgy linked list to doubly linked list?

I have a program that I am supposed to change it from a singly linked list to a doubly linked list. This means that I use pointer that points to the next node and a pointer that points to previous node.
How do I do this while recycling my previous code. Is there a way to do this with minimum steps involved?
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
//declaring structure
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
}node;
//prototypes
node *create(int n);
void display_recursive(node *n);
int main()
{
int n = 0;
node *head = NULL;
printf("How many entries?\n");
scanf("%d", &n);
//call to create list
head = create(n);
printf("\nThe linked list in order is:\n");
display_recursive(head);
return 0;
}
node *create(int n)
{
node *head = NULL;
node *temp = NULL;
node *p = NULL;
for (int i = 0; i < n; i++)
{
temp = (node*)malloc(sizeof(node));
printf("What is the name of song %d\n", i + 1);
scanf("%s", &temp->songName);
printf("What is the length of song %d (in seconds)?\n", i + 1);
scanf("%d", &temp->songLength);
printf("Is song %d copyrighted?(1 = YES, 0 = NO)\n", i + 1);
scanf("%d", &temp->copyright);
temp->next = NULL;
if (head == NULL)
{
head = temp;
}
else
{
// if not empty, attach new node at the end
p = head;
while (p->next != NULL)
{
p = p->next;
}
p->next = temp;
}
}
return head;
}
void display_recursive(node *n) {
if (!n) {
return;
}
display_recursive(n->next);
printf("Song: %s, ", n->songName);
printf("%d minutes, ",n->songLength);
if (n->copyright == 1)
{
printf("Copyrights\n");
}
else if (n->copyright == 0)
{
printf("No copyrights\n");
}
}
I don't really know how the code should look or what I have to add to achieve a doubly linked list.
You just need a pointer point to previous node
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
struct node* prev;
}node;
just like #T1412 said, you need to add a new member to the structure.
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
struct node* prev;
}node
now you need to modify the create() function so that each node's prev pointer is pointing to previous node, and the HEAD node's prev points to NULL.
Similarly, you need to modify all the linked list related functions to incorporate the prev pointer.
1) strongly suggest changing:
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
}node;
to:
struct NODE
{
char songName[20];
int songLength;
int copyright;
struct NODE * prev;
struct NODE * next;
};
typedef struct NODE node;
Then wherever in the code that it is linking in a new node, add the necessary statement to set the 'prior' field. Remember that the firs node will contain NULL in the 'prior' field.

How do you get a data section from a Linked list to compare?

I have just started learning linked list and was messing around with it but then I ran into a problem. I was not sure how to access the data member to actually compare it. In my code, I prompt the user to input grades and when they input -1 then it signals that they are finished. My first thought was to get the pointer pointing to the node to get the data like I did in scanf, however I can't compare pointers to integers. Is there a way to get data members from linked lists to compare? Also, pointing out other errors would be appreciated as well because I don't know linked lists too well. I have the following code:
int main() {
struct Node
{
int grade;
struct Node *next;
};
struct Node *head;
struct Node *first;
struct Node *temp = 0;
first = 0;
while (****** != -1) { //This is what I need the data from linked list for
head = (struct Node*)malloc(sizeof(struct Node));
printf("Enter the grade: \n ");
scanf("%d", &head -> grade);
if (first != 0) {
temp -> next = head;
temp = head;
}
else
{
first = temp = head;
}
}
}
There is a number of issue with your code:
1) Don't scan directly into the list - use a temp variable
2) Always check return values
3) Make sure to initialize variables, i.e. head
Try something like:
struct Node
{
int grade;
struct Node *next;
};
int main() {
struct Node *head = NULL;
struct Node *temp;
int data;
while (1)
{
printf("Enter the grade: \n ");
if (scanf("%d", &data) != 1)
{
// Illegal input
exit(1);
}
if (data == -1) break; // Stop the loop
temp = malloc(sizeof *temp); // Allocate new element
if (temp == NULL)
{
// Out of mem
exit(1);
}
temp -> next = head; // Insert new element in the front of list
temp -> grade = data;
head = temp; // Move the front (aka head) to the new element
}
// .... add code that uses the list
return 0;
}

Applying Singly Linked List in C

Creating a list in C implementing SLL.
struct dat
{
char fname[20];
char lname[20];
};
typedef struct node_s
{
struct dat data;
struct node_s *next;
}NODE;
NODE *list=NULL;
NODE *list_create(struct dat *data)
{
NODE *node;
if(!(node=malloc(sizeof(NODE))))
{
return NULL;
}
node->data = data;
node->next = NULL;
return node;
}
NODE *list_insert_after(NODE *node, struct dat *data)
{
NODE *newnode;
newnode = list_create(data);
newnode->next = node->next;
node->next = newnode;
return newnode;
}
I cant find any good examples using SLL.
Now i have this append function now i will apply the two SLL functions, list_create and list_insert_after.
Is this correct?
void app(struct dat x)
{
FILE *fp;
fp=fopen("database.dat","a");
if(fp==NULL)
{
printf("file error");
}
if(fp!=NULL)
{
printf("enter lname: ");
gets(x.lname);
printf("enter fname: ");
gets(x.fname);
fprintf(fp,"%s %s\n",x.lname,x.fname);
if(list == NULL)
{
list=list_create((&x));
}
else
{
next=list_insert_after(list,&x);
}
}
fclose(fp);
}
To complete your example you should decide:
a) what if the role of your file database.dat.
b) how you work with your list.
I suppose you need two pointers to operate with the list: a pointer to the first element (it is list I think) and pointer to the last element (may be it is next).
Now call such as list_insert_after(list,&x); always inserts element after the first element, so your list cannot be longer than 2.
Consider the changes in your code as follows:
if(list == NULL)
{
list = list_create((&x));
next = list; // the last is the first
}
else
{
next=list_insert_after(next,&x); // insertion after the last
}
And about the file: if you decide to store not strings in text file, but structures in the binary file, save only struct dat to file, because storing pointers has no sense.
Even if C is a low level language, it is not forbidden to structure data. The node should be an internal object of the list. How to implement it in C depends on how you want to use it. Some examples :
a FIFO stack : 2 functions push and pop, and the list only needs to retain the last added element (you won't add after but before - left as an exercise)
a LIFO queue : still only 2 functions add and take, and the list needs to retain first element (its head) because its the next that will be taken, and last one (its tail) because it is where you will add next
typedef struct list_s {
NODE *head;
NODE *tail;
int len;
} LIST;
int add(LIST *list, struct dat *data) {
list->tail = list_insert_after(list->tail, data);
list->len += 1;
return list->len;
}
struct dat * take(LIST *list) {
if (list->len == 0) return NULL;
struct dat *data = head->data;
NODE *n = head;
head = head->next;
free(n);
return data;
}
of course, you will have to initialize a list, could take its length, ...
a true list : internally the same as a LIFO, but you will have to define an iterator (only contains a NODE *), and for example a BOOL hasnext(*ITERATOR) and struct dat * next(*ITERATOR)
the remaining is only limited by your requirements
NB: I assumed NODE.data was a struct dat * not a struct dat ...

How to determine height and length of a 2D array from stdin?

My program has to read contents of a file like so:
name_of_program < Test.txt
Test.txt is a 2D array of integers (integers are separated by spaces, sometimes multiple ones, rows of integers are separated by EOL), but of unknown length and height. How do I determine them?
I plan on storing each row in a node of a linked list as an array of integers.
EDIT: My program roughly looks like this:
#include <stdio.h>
#include <stdlib.h>
struct node {
int *val; //stores the row
struct node *next;
};
struct node *addnode(int *val, struct node *next);
struct node *mergesort(struct node *head, int column); //column by which I'll sort it
struct node *merge(struct node *head_one, struct node *head_two, int column);
int main(int column) //number of column to sort by, should run like that "name_of_program column < Test.txt" in Unix systems
{
struct node *head;
struct node *current;
struct node *next;
head = NULL;
/* Reading from stdin line by line, writing it to list and linking nodes - I have only the last bit done */
head = mergesort(head, column);
/* Writing to stdout, row by row of sorted list, I can't do that without the previous bit */
for(current = head; current != NULL; current = next)
next = current->next, free(current);
return 0;
};
struct node *addnode(int *val, struct node *next)
{
struct node *tnode;
tnode = (struct node*)malloc(sizeof(*tnode));
if(tnode != NULL) {
tnode->val = val; //not sure about this line, would it write whole array, or just one element?
tnode->next = next;
};
return tnode;
}
struct node *mergesort(struct node *head, int column)
{
struct node *head_one;
struct node *head_two;
if((head == NULL) || (head->next == NULL))
return head;
head_one = head;
head_two = head->next;
while((head_two != NULL) && (head_two->next != NULL)) {
head = head->next;
head_two = head->next->next;
};
head_two = head->next;
head->next = NULL;
return merge(mergesort(head_one, column), mergesort(head_two, column), column);
}
struct node *merge(struct node *head_one, struct node *head_two, int column)
{
struct node *head_combined;
if(head_one == NULL)
return head_two;
if(head_two == NULL)
return head_one;
if(head_one->val[column] < head_two->val[column]) {
head_combined = head_one;
head_combined->next = merge(head_one->next, head_two, column);
} else {
head_combined = head_two;
head_combined->next = merge(head_one, head_two->next, column);
};
return head_combined;
}
You can start by reading file line by line in C you can use getline function.
You will need to allocate sufficiently large buffer considering maximum length of line.
Process the line, retrieving integers from line, this can be done by looping through line buffer
and skipping white spaces. The integers can be stored either in 2D array or linked list which you can created.

Resources