FILE reading and sorting a link list - c

It seems my FILE reading function is slightly off. Instead of printing all the data (First Name: Last Name: priority: Reading Level:) per entry when I call my print function it stops after two and just has the skeleton of what needs to be printed there for the last three entries. And because of that, when I then call my sort function based off priority level in each struct link list, I can't tell if it's printing correctly.
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#define NAME 25
#define TITLE 50
typedef struct Book{
int bookID;
char* title;
bool checkedOut;
struct Book* next;
}book;
typedef struct Student{
char* firstName;
char* lastName;
int priority;
int readingLevel;
book* backPack;
bookids* wishlist;
struct Student* next;
}student;
student* buildStudentList(char* studentFile, student* head)
{
FILE *cfptr=fopen(studentFile, "r");
if(cfptr==NULL){
printf("\nFIle could not be opened\n");
return 0;
}
if(head==NULL){
head=malloc(sizeof(student));
head->next=NULL;
head->firstName=malloc(sizeof(student)*35);
head->lastName=malloc(sizeof(student)*35);
fscanf(cfptr,"%s %s %d %d", head->firstName,head->lastName,
&head->priority, &head->readingLevel);
}
student* current=head;
while(current->next!=NULL){
current=current->next;
}
current->next=malloc(sizeof(student));
current=current->next;
current->firstName=malloc(sizeof(student)*35);
current->lastName=malloc(sizeof(student)*35);
while( fscanf(cfptr, "%s %s %d %d", current->firstName, current->lastName,
&current->priority, &current->readingLevel)!=EOF){
student* current=head;
while(current->next!=NULL){
current=current->next;
}
current->next=malloc(sizeof(student));
current=current->next;
current->firstName=malloc(sizeof(student)*35);
current->lastName=malloc(sizeof(student)*35);
}
return head;
}
void createPriorityQueue(student* head)
{
if(head==NULL ||head->next==NULL){
return;
}
student* curr; student* largest; student* largestPrev; student* prev;
curr=head;
largest=head;
prev=head;
largestPrev=head;
while(curr!=NULL){
if(&curr->priority>&largest->priority){
largestPrev=prev;
largest=curr;
}
prev=curr;
curr=curr->next;
}
student* tmp;
if(largest!=head)
{
largestPrev->next=head;
tmp=head->next;
head->next=tmp;
}
}

There are a few bugs.
The malloc for allocation of strings should be malloc(35) and not malloc(sizeof(student) * 35). It won't crash but it's wasteful.
Your build function was way too complicated and had several bugs--I had to recode it.
Your priority queue function was comparing addresses of priority instead of values [what we want].
Anyway, here's your code with some annotations for the bugs and a recoded create function [please pardon the gratuitous style cleanup]:
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#define NAME 25
#define TITLE 50
typedef struct Book {
int bookID;
char *title;
bool checkedOut;
struct Book *next;
} book;
typedef struct Student {
char *firstName;
char *lastName;
int priority;
int readingLevel;
book *backPack;
bookids *wishlist;
struct Student *next;
} student;
// NOTE/BUG: this function is way to complicated -- see below for a simpler one
student *
buildStudentList(char *studentFile, student * head)
{
FILE *cfptr = fopen(studentFile, "r");
if (cfptr == NULL) {
printf("\nFIle could not be opened\n");
return 0;
}
if (head == NULL) {
head = malloc(sizeof(student));
head->next = NULL;
// NOTE/BUG: we want just enough to store strings -- this is true for all the
// other mallocs that allocate names
#if 0
head->firstName = malloc(sizeof(student) * 35);
head->lastName = malloc(sizeof(student) * 35);
#else
head->firstName = malloc(35);
head->lastName = malloc(35);
#endif
fscanf(cfptr, "%s %s %d %d",
head->firstName, head->lastName, &head->priority,
&head->readingLevel);
}
student *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(student));
current = current->next;
current->firstName = malloc(sizeof(student) * 35);
current->lastName = malloc(sizeof(student) * 35);
while (fscanf(cfptr, "%s %s %d %d",
current->firstName, current->lastName, &current->priority,
&current->readingLevel) != EOF) {
student *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(student));
current = current->next;
current->firstName = malloc(sizeof(student) * 35);
current->lastName = malloc(sizeof(student) * 35);
}
// NOTE/BUG: close input file
#if 1
fclose(cfptr);
#endif
return head;
}
// simplified version
student *
buildStudentList(char *studentFile, student * head)
{
FILE *cfptr = fopen(studentFile, "r");
student *current;
student *tail;
char firstName[5000];
char lastName[5000];
if (cfptr == NULL) {
printf("\nFIle could not be opened\n");
return 0;
}
// find last element in list
tail = NULL;
for (current = head; current != NULL; current = current->next)
tail = current;
while (1) {
// allocate new node
current = malloc(sizeof(student));
// initialize the next pointer (in a singly linked list, this is nulled)
current->next = NULL;
// get data for new node
if (fscanf(cfptr, "%s %s %d %d",
firstName, lastName, &current->priority,
&current->readingLevel) == EOF) {
free(current);
break;
}
// allocate space for strings
current->firstName = strdup(firstName);
current->lastName = strdup(lastName);
// add to empty list
if (head == NULL)
head = current;
// add to tail of list
else
tail->next = current;
// set this as new tail of list
tail = current;
}
fclose(cfptr);
return head;
}
void
createPriorityQueue(student * head)
{
if (head == NULL || head->next == NULL) {
return;
}
student *curr;
student *largest;
student *largestPrev;
student *prev;
curr = head;
largest = head;
prev = head;
largestPrev = head;
while (curr != NULL) {
// NOTE/BUG: this compares _addresses_ but we want to compare values
#if 0
if (&curr->priority > &largest->priority) {
#else
if (curr->priority > largest->priority) {
#endif
largestPrev = prev;
largest = curr;
}
prev = curr;
curr = curr->next;
}
student *tmp;
if (largest != head) {
largestPrev->next = head;
tmp = head->next;
head->next = tmp;
}
}
UPDATE:
how do I make the createpriority function sort in the opposite order, its form highest to lowest, i need lowest to highest?
Not sure exactly which order you want now or what changes you've already made. In your original code, you were only doing a single pass on the list instead of as many passes as there were elements.
I've fixed the original code to do the correct number of passes, using simple insertion/selection. This is slow. You could speed it up by doing a mergesort on the linked list, but that's more involved.
Anyway, here's the code. I didn't test it or even compile it but it should get you closer:
student *
createPriorityQueue(student *head)
{
student *curr;
student *bestCurr;
student *bestPrev;
student *prev;
student *tail;
student *rtn;
// initialize sorted list
rtn = NULL;
tail = NULL;
// process all elements of unsorted list
while (head != NULL) {
// assume head of unsorted list is best priority in unsorted list
bestCurr = head;
bestPrev = NULL;
// find best in unsorted list
prev = NULL;
for (curr = head; curr != NULL; curr = curr->next) {
#ifdef SORT_LOW_TO_HIGH
if (curr->priority < bestCurr->priority) {
bestCurr = curr;
bestPrev = prev;
}
#else
if (curr->priority > bestCurr->priority) {
bestCurr = curr;
bestPrev = prev;
}
#endif
prev = curr;
}
// remove element from unordered list
if (bestPrev != NULL)
bestPrev->next = bestCurr->next;
else
head = bestCurr->next;
// add the next best priority to the end of the ordered list
if (tail != NULL)
tail->next = bestCurr;
else
rtn = bestCurr;
// set new tail of ordered list
tail = bestCurr;
tail->next = NULL;
}
return rtn;
}

Related

I need to create a single linked list by taking the input from a file i.e., .txt file and print the linked list

The .txt file consists of id, name, gender, occupation, age. Now I need to read from the file and create a linked list and print the list. The code should be in C language.
below is the code which I am trying, but only a string/ word is printing.
Do I need to use fscanf function in while loop instead of fgets function? I need to print all the contents of text file, which has both integer and character type in it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
char *string;
struct list *next;
};
typedef struct list LIST;
int main(void) {
FILE *fp;
char line[128];
LIST *current, *head;
head = current = NULL;
fp = fopen("hello.txt", "r");
while(fgets(line, sizeof(line), fp)){
LIST *node = malloc(sizeof(LIST));
node->string = strdup(line);
node->next =NULL;
if(head == NULL){
current = head = node;
} else {
printf("%s", current->string);
current = current->next = node;
}
}
fclose(fp);
for(current = head; current ; current=current->next){
// printf("%s", current->string);
}
return 0;
}
This is wrong since it will never print the last line you read:
if(head == NULL){
current = head = node;
} else {
printf("%s", current->string); // prints the previous line
current = current->next = node;
}
If you want all lines to be printed, do the printing after you've assigned current:
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
printf("%s", current->string);
Or before assigning current, using node:
printf("%s", node->string);
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
I would also suggest organizing the code and make use of functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list LIST;
struct list {
char *string;
LIST *next; // I moved the typedef above the struct list definition
};
// A function to read and populate a list from a stream:
LIST *list_read(FILE *fp) {
char line[128];
LIST *head, **tail = &head;
while (fgets(line, sizeof line, fp)) {
LIST *node = malloc(sizeof *node);
node->string = strdup(line);
// simplification of your `if(head == NULL)` code. No `if`s needed:
*tail = node;
tail = &node->next;
}
*tail = NULL;
return head;
}
// A function to free the resources allocated by a list
void list_free(LIST *head) {
for (LIST *current = head, *next; current; current = next) {
next = current->next;
free(current->string);
free(current);
}
}
// A function to print a list
void list_print(LIST *head) {
for (LIST *current = head; current; current = current->next) {
printf("%s", current->string);
}
}
int main(void) {
FILE *fp = fopen("hello.txt", "r");
if (fp == NULL) return 1;
LIST *head = list_read(fp);
fclose(fp);
list_print(head);
list_free(head);
}
If you want the list to be sorted in alphabetical order, you could add a function that inserts a node in the correct position in the list:
void list_insert(LIST **lp, char *str) {
LIST *node = malloc(sizeof *node);
node->string = strdup(str);
// find insertion point for the list to be in alphabetical order
while(*lp && strcmp(str, (*lp)->string) > 0) {
lp = &(*lp)->next;
}
// link the new node:
node->next = *lp;
*lp = node;
}
and change list_read accordingly:
LIST *list_read(FILE *fp) {
char line[128];
LIST *head = NULL;
while (fgets(line, sizeof line, fp)) {
list_insert(&head, line);
}
return head;
}

I set head to be something but it is always null

I am simply just trying to print out my doubly linked list. However, even though I clearly set my head and tail to something, it is always NULL when I print it in main. I am unsure on what the issue is. I've tried to simplify the code as much as I can.
In the function grade_word_gen you can clearly see I set head to something and I set tail to something.
test.txt
*A*
Great
Fantastic
Lovely
*B*
Bad
Not Good
Terrible
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct grade {
struct grade_word *A_head;
struct grade_word *A_tail;
struct grade_word *B_head;
struct grade_word *B_tail;
};
struct grade_word {
char *word;
struct grade_word *next;
struct grade_word *prev;
};
struct grade *create_grade() {
struct grade *new_grade = malloc(sizeof(struct grade));
// Check grade was allocated correctly
if (new_grade == NULL) {
fprintf(stderr, "ERROR: Could not allocate memory for grade\n");
exit(1);
}
// Initialise all variables
new_grade->A_head = NULL;
new_grade->A_tail = NULL;
new_grade->B_head = NULL;
new_grade->B_tail = NULL;
return new_grade;
}
struct grade_word *create_grade_word(char *word) {
struct grade_word *new = malloc(sizeof(struct grade_word));
if (new == NULL) {
fprintf(stderr, "ERROR: Unable to allocate memory for grade_words\n");
exit(1);
}
// Initialise vairables
int len = strlen(word);
new->word = malloc(sizeof(char) * (len + 1));
strcpy(new->word, word);
new->next = NULL;
new->prev = NULL;
return new;
}
void grade_word_gen(struct grade *grade_data) {
FILE *fp = fopen("test.txt", "r");
char grade;
char buf[100 + 1];
struct grade_word *new_node;
struct grade_word *head;
struct grade_word *tail;
while (fgets(buf, 100, fp) != NULL) {
if (buf[0] == '*' && buf[2] == '*') {
grade = buf[1];
} else {
new_node = create_grade_word(buf);
// Set next, prev, head, tail pointers
if (grade == 'A') {
head = grade_data->A_head;
tail = grade_data->A_tail;
} else {
head = grade_data->B_head;
tail = grade_data->B_tail;
}
// If first item set the head
if (head == NULL) {
head = new_node;
//printf("head: %s\n", head->word);
// Otherwise just add on to the list
} else {
new_node->prev = tail;
tail->next = new_node;
}
tail = new_node;
}
// Reset buffer
strcpy(buf, "\0");
}
}
void print_grade_list(struct grade_word *list, char grade) {
if (list == NULL) {
printf("Grade %c is empty, so not grade words can be printed\n", grade);
return;
}
printf("Grade: %c\n", grade);
while (list != NULL) {
printf("%s\n", list->word);
list = list->next;
}
}
int main(void) {
struct grade *new_grade = create_grade();
grade_word_gen(new_grade);
print_grade_list(new_grade->A_head, 'A');
print_grade_list(new_grade->B_head, 'B');
}
My output is always Grade %c is empty, so not grade words can be printed. I don't understand why my head is always null, even though I do set it.
You never assign anything to A_head except in the initialization part where you assign NULL. Consequently A_head will remain at NULL:
The problem is here:
if (grade == 'A') {
head = grade_data->A_head; // Here you make head equal A_head
tail = grade_data->A_tail;
} else {
head = grade_data->B_head;
tail = grade_data->B_tail;
}
// If first item set the head
if (head == NULL) {
head = new_node; // Here you try to save new_node.
// But you save it into head and that will not
// change A_head
You need to have code like:
grade_data->A_head = new_node;
so that you actually change A_head.
An alternative way so that you can share the code between case A and B is double pointers. Like:
// Make a double pointer
struct grade_word **head;
. . .
// Make it point to either the A or B head pointer
head = &grade_data->A_head; // or head = &grade_data->B_head;
. . .
// Change A or B head pointer using head
*head = new_node;

Printing elements in a linked list based on a user inputted prefix in C

I am currently writing an auto-complete program in C and am in need of some help (yes this is a hw assignment). Basically what the program does is asks the user to input a folder name and then adds all of the directories in that folder into a linked list. The user is then asked to input a prefix and the program will print all of the directories that begin with said prefix.
My question is how do I implement a function to print out all directories with the prefix?
(i have already created the linked list I just need to print out the directories based on the prefix)
sample output:
Enter a folder name: /usr/bin
> zi
Files starting with zi in /usr/bin:
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
> zipc
Files starting with zipc in /usr/bin:
zipcloak
code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
const int MAX = 125;
//node struct
typedef struct Node{
//fn length
char fn[256];
struct Node *next;
}Node;
//list struct
typedef struct List {
struct Node *head;
} List;
//constants and functions
char *getNext(DIR *dp);
List *create();
void addElement(List *list, char *v);
void printList(List *list);
void printFIles(List *fn, char prefix);
int main(void) {
// insert code here...
//variables
char dirName[MAX];
char prefix[MAX];
int i = 0;
List *fileNames[26];
DIR *dp;
char *fn;
struct dirent *ep;
char dir[MAX];
//enter a directory
printf("Enter a folder name: ");
scanf("%s", dirName);
dp = opendir(dirName);
for (i =0; i<26; i++) {
fileNames[i] = create();
}
if (dp != NULL)
{
while ((ep = readdir (dp)) != NULL) {
strcpy(dir, ep->d_name); /* adds to list */
addElement(fileNames, dir);
}
(void) closedir (dp); /*close the directory */
}
else{
perror ("Couldn't open the directory");
}
printf(">");
while (scanf("%s", prefix)) {
printf("Files starting with %s in %s \n", prefix, dirName);
}
return 0;
}
void addElement(List *list, char *v){
//adds a node to the top of list
Node *head = list->head;
//if the head isnt null push it to the front of the list
if (head != NULL) {
Node *newnode = malloc(sizeof(Node));
strcpy(newnode->fn, v);
//set the next node equal to the head of the list
newnode->next = list->head;
list->head = newnode;
return;
}
Node *current = head;
Node *next = current->next;
if (next == NULL) {
current = next;
next = next->next;
}
if(next !=NULL){
//push to end
Node *current = list->head;
Node *node = malloc(sizeof(Node));
strcpy(node->fn, v);
node ->next = NULL;
while (current->next == NULL) {
current = current->next;
}
if (current) {
current->next =node;
} else{
list->head = node;
}
return;
}
Node *node = malloc(sizeof(Node));
strcpy(node->fn, v);
current ->next = node;
node -> next = next;
}
void printList(List *list) {
Node *current = list->head;
printf("[");
//iterate
while (current != NULL) {
printf("%s", current->fn);
if (current->next) {
printf(",");
}
current = current->next;
}
printf("]");
}
void printFIles(List *fn, char prefix){
// Node *node = list->head;
//
// while (node && ) {
// <#statements#>
}
List *create(){
//allocate memory for the lsit
List *list = malloc(sizeof(List));
list->head = NULL; /*head of list is now null*/
return list;
}

How to pass a linked list to a function in C

So I have made a working program for getting data from a file and printing out the file according to which part of the file you want all within main. But my goal is to make this modular, by creating a user interface and either appending to the linked list from the file or printing out a part of that linked list (if any) as requested.
There's just one problem: I can't seem to figure out a way to successfully pass a linked list to the function so that when you create new nodes in the function (Append), it will also work in main and then back again in (Print).
Here's the working code:
#include <stdio.h>
#include <stdlib.h> /* has the malloc prototype */
#define TSIZE 100 /* size of array to hold title */
struct book {
char title[TSIZE], author[TSIZE],year[6];
struct book * next; /* points to next struct in list */
};
//typedef struct book ITEM;
typedef struct book * Node; // struct book *
void Append(Node *List, Node *Lcurrent,char filename[]);
void ClearGarbage(void);
int main(void){
Node head=NULL;
Node current;
current=head;
char fname[]="HW15Data.txt";
char op;
do{
puts("Select operation from the following list:");
puts("a. Append p. Print q. quit");
op = getchar();
ClearGarbage();
if (op=='a'){
/* Gather and store information */
Append(&head,&current,fname);
}
else if (op=='q'){
/* User quit, so free allocated memory */
current = head;
while (current != NULL)
{
free(current);
current = current->next;
}
printf("Bye!\n");
return 0;
}
else{
/* Program done, so free allocated memory */
current = head;
while (current != NULL)
{
free(current);
current = current->next;
}
printf("Invalid characted entered. Bye!\n");
return 0;
}
} while (op!='q');
return 0;
}
void Append(Node *List, Node * Lcurrent,char filename[TSIZE]){
FILE * fp;
Node head=*List;
Node current=*Lcurrent;
int loops=0;
fp=fopen(filename,"r");
if (head==NULL){
head=(Node) malloc(sizeof(struct book));
current=head;
current->next=NULL;
}
do{
current->next = (Node) malloc(sizeof(struct book));
current=current->next;
loops++;
} while(fgets(current->title,sizeof(current->title),fp) && fgets(current->author,sizeof(current->title),fp) && fgets(current->year,sizeof(current->year),fp));;
free(current);
printf("Number of records written: %d\n",loops);
//Same as Print function in the nonworking code
int num;
int i=0;
if (head == NULL){
printf("No data entered. ");
}
else{
printf("Enter record # to print: ");
scanf("%d",&num);
ClearGarbage();
num=num+1;
current = head;
while (current != NULL && i<num)
{
for (i=0;i<num;i++)
current = current->next;
printf("Book: %sAuthor: %sYear: %s\n",
current->title, current->author, current->year);
}
}
}
void ClearGarbage(void){
while (getchar()!='\n');
}
Okay cool that works, but my guess is that as soon as Append is done, the nodes made in Append are useless in main because they are now gone. So when I try to make a Print function in the following code, there's nothing to print.
#include <stdio.h>
#include <stdlib.h> /* has the malloc prototype */
#define TSIZE 100 /* size of array to hold title */
struct book {
char title[TSIZE], author[TSIZE],year[6];
struct book * next; /* points to next struct in list */
};
//typedef struct book ITEM;
typedef struct book * Node; // struct book *
void Append(Node *List, Node *Lcurrent,char filename[]);
int Print(Node *List,Node *Lcurrent);
void ClearGarbage(void);
int main(void){
Node head=NULL;
Node current;
current=head;
char fname[]="HW15Data.txt";
char op;
do{
puts("Select operation from the following list:");
puts("a. Append p. Print q. quit");
op = getchar();
ClearGarbage();
if (op=='a'){
/* Gather and store information */
Append(&head,&current,fname);
}
else if (op=='p'){
/*Print book record of user's choice*/
Print(&head,&current);
}
else if (op=='q'){
/* User quit, so free allocated memory */
current = head;
while (current != NULL)
{
free(current);
current = current->next;
}
printf("Bye!\n");
return 0;
}
else{
/* Program done, so free allocated memory */
current = head;
while (current != NULL)
{
free(current);
current = current->next;
}
printf("Invalid characted entered. Bye!\n");
return 0;
}
} while (op!='q');
return 0;
}
void Append(Node *List, Node * Lcurrent,char filename[TSIZE]){
FILE * fp;
Node head=*List;
Node current=*Lcurrent;
int loops=0;
fp=fopen(filename,"r");
if (head==NULL){
head=(Node) malloc(sizeof(struct book));
current=head;
current->next=NULL;
}
do{
current->next = (Node) malloc(sizeof(struct book));
current=current->next;
loops++;
} while(fgets(current->title,sizeof(current->title),fp) && fgets(current->author,sizeof(current->title),fp) && fgets(current->year,sizeof(current->year),fp));
free(current);
printf("Number of records written: %d\n",loops);
}
int Print(Node *List,Node *Lcurrent){
int num;
int i=0;
Node head=*List;
Node current=*Lcurrent;
if (head == NULL){
printf("No data entered.\n");
return -1;
}
printf("Enter record # to print: ");
scanf("%d",&num);
ClearGarbage();
num=num+1;
current = head;
while (current != NULL && i<num)
{
for (i=0;i<num;i++){
current = current->next;
}
printf("Book: %sAuthor: %sYear: %s\n",
current->title, current->author, current->year);
}
return 0;
}
void ClearGarbage(void){
while (getchar()!='\n');
}
Thanks anyone for any help!
EDIT: Got rid of an unused typedef for clarity
It seems like most of the people are focusing the lack of organization (it bother me a lot too) instead of your actual issue.
Seems like the source of your issue is where you assign the variable head.
when you define "Node head = *List" and List is NULL, as it's first initialized, it loses the connection it had to the original list you sent from main, and you just create a linked list with a local reference only.
I just changed the uses of "head" to "*List" within the Append and Print functions and it seems to sort it out.
This is your code after my changes:
#include <stdio.h>
#include <stdlib.h> /* has the malloc prototype */
#define TSIZE 100 /* size of array to hold title */
struct book {
char title[TSIZE], author[TSIZE], year[6];
struct book * next; /* points to next struct in list */
};
//typedef struct book ITEM;
typedef struct book * Node; // struct book *
void Append(Node *List, Node *Lcurrent, char filename[]);
int Print(Node *List, Node *Lcurrent);
void ClearGarbage(void);
int main(void) {
Node head = NULL;
Node current;
current = head;
char fname[] = "HW15Data.txt";
char op;
do {
puts("Select operation from the following list:");
puts("a. Append p. Print q. quit");
op = getchar();
ClearGarbage();
if (op == 'a') {
/* Gather and store information */
Append(&head, &current, fname);
}
else if (op == 'p') {
/*Print book record of user's choice*/
Print(&head, &current);
}
else if (op == 'q') {
/* User quit, so free allocated memory */
current = head;
while (current != NULL)
{
free(current);
current = current->next;
}
printf("Bye!\n");
return 0;
}
else {
/* Program done, so free allocated memory */
current = head;
while (current != NULL)
{
free(current);
current = current->next;
}
printf("Invalid characted entered. Bye!\n");
return 0;
}
} while (op != 'q');
return 0;
}
void Append(Node *List, Node * Lcurrent, char filename[TSIZE]) {
FILE * fp;
Node head = *List;
Node current = *Lcurrent;
int loops = 0;
char line[256];
fp = fopen(filename, "r");
if (*List == NULL) {
*List = (Node)malloc(sizeof(struct book));
current = *List;
current->next = NULL;
}
do {
current->next = (Node)malloc(sizeof(struct book));
current = current->next;
loops++;
} while (fgets(current->title, sizeof(line), fp) && fgets(current->author, sizeof(line), fp) && fgets(current->year, sizeof(line), fp));
free(current);
printf("Number of records written: %d\n", loops);
}
int Print(Node *List, Node *Lcurrent) {
int num;
int i = 0;
Node head = *List;
Node current = *Lcurrent;
if (*List == NULL) {
printf("No data entered.\n");
return -1;
}
printf("Enter record # to print: ");
scanf("%d", &num);
ClearGarbage();
num = num + 1;
current = *List;
while (current != NULL && i<num)
{
for (i = 0; i<num; i++) {
current = current->next;
}
printf("Book: %sAuthor: %sYear: %s\n",
current->title, current->author, current->year);
}
return 0;
}
void ClearGarbage(void) {
while (getchar() != '\n');
}
There are still many logical errors, and some bugs, but it fixes the problem you asked help for.

C Programming - Sorting structs as they enter your linked list

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ENTRY 100
//define struct
typedef struct StudentRecords
{
int StudentID; //must be of size 7 between 1000000 and 9999999
char *Firstname; //= MALLOC(256*sizeof(char)); // must be any length and allocate memory dynamically.
char *Lastname; //= MALLOC(256*sizeof(char));
char *Department; //= MALLOC(256*sizeof(char));
float GPA; // must be between 0 and 4
} STUDENTRECORDS;
//define linked list structs
struct Node
{
struct StudentRecords data;
struct Node* next;
struct Node* prev;
};
//define global head
struct Node* head;
struct Node* GetNewNode(struct StudentRecords Record)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = Record;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
//create a function to use the struct
void Insert(struct StudentRecords Record)
{
struct Node* newNode = GetNewNode(Record);
if (head==NULL)
{
head = newNode;
return;
}
head->prev = newNode;
newNode->next = head;
head= newNode;
}
void Print() {
struct Node* temp = head;
printf("StudentID: ");
while (temp != NULL)
{
printf("%d\n", temp->data.StudentID);
temp = temp->next;
}
}
void ReversePrint()
{
struct Node* temp = head;
if (temp == NULL)
{
return;
}
while (temp->next != NULL)
{
temp = temp->next;
}
printf("Reverse: ");
while (temp!= NULL)
{
printf("%d", temp->data);
temp = temp->prev;
}
printf("\n");
}
int main()
{
/*
First job is read the file
*/
//set variables
int i=0;
char filecontent, file_name[100];
FILE *fp;
STUDENTRECORDS StudentRecords[MAX_ENTRY];
for(i=0;i<MAX_ENTRY;i++)
{
StudentRecords[i].Firstname = malloc(sizeof(char)*256);
StudentRecords[i].Lastname = malloc(sizeof(char)*256);
StudentRecords[i].Department = malloc(sizeof(char)*256);
}
printf("Enter directory of file\n"); // instructs user to enter directory of file
gets(file_name); //prompt use
fp = fopen(file_name,"r"); //opens the file "r" is read mode for fopen()
// here is a check to see if fp is empty and throw an error if so
if (fp == NULL)
{
perror("Could not open file\n");
//exit(EXIT_FAILURE);
}
//this adds the content to the struct we created.
// and prints it
i=0;
printf("Records in struct:\n");
while(EOF!=fscanf(fp, "%d %s %s %s %f\n", &StudentRecords[i].StudentID, StudentRecords[i].Firstname, StudentRecords[i].Lastname, StudentRecords[i].Department, &StudentRecords[i].GPA))
{
printf("%d %s %s %s %f\n", StudentRecords[i].StudentID, StudentRecords[i].Firstname, StudentRecords[i].Lastname, StudentRecords[i].Department, StudentRecords[i].GPA);
i++;
}
printf("Creating linked list of structs...\n");
//Now we have to add it to a linked list.
for (i=0; i < sizeof(StudentRecords)/sizeof(StudentRecords[0]); i++)
Insert(StudentRecords[i]);
//Insert(StudentRecords[0]);
//Insert(StudentRecords[1]);
//print function for linked list
printf("Printing linked list...\n");
Print();
// fclose() must follow an fopen()
fclose(fp);
return 0;
}
Here is my entire code for a program I'm writing. I am to input a text file that looks like this:
2040003 AAAA BBBBBBBBB ComputerScience 3.4
2040002 AAA CCC ElectricalEngineering 3.01
2040005 AAAAAAAAAAAAAAAAA BBB ComputerScience 3.60
The output is to be sorted the the first int, or StudentID and separated by commas
2040002,AAA,CCC,ElectricalEngineering,3.01
2040003,AAAA,BBBBBBBBB,ComputerScience,3.45
2040005,AAAAAAAAAAAAAAAAA,BBB,ComputerScience,3.60
I was thinking of sorting the structs as they enter the linked list, rather than after. I think I can alter my Insert() function to place them in the right order, but everything I've tried hasn't worked. So here's the code with it simply printing the list without any sorting.
Thanks for any suggestions or pointers.
Your insert function should look something like this
void Insert(struct StudentRecords Record)
{
struct Node* newNode = GetNewNode(Record);
struct Node *tmp = head;
/* Check if we need to insert at head */
if (head==NULL)
{
head = newNode;
return;
}
/* Check if new node is smaller than head */
if (head->data.StudentID > Record.StudentID) {
head->prev = newNode;
newNode->next = head;
head = newNode;
return;
}
/* Find the node previous to node having StudentID > "StudentID in new node" */
while(tmp->next && tmp->next->data.StudentID < Record.StudentID)
tmp = tmp->next;
/* Insert the new node */
newNode->next = tmp->next;
if (tmp->next)
tmp->next->prev = newNode;
tmp->next = newNode;
newNode->prev = tmp;
}

Resources