user_191998
user_191998

Reputation: 31

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;
}

Upvotes: 2

Views: 129

Answers (1)

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

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;
}

Upvotes: 1

Related Questions