2

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;
}
user438383
  • 5,716
  • 8
  • 28
  • 43
  • 3
    This seems like a very good time to learn how to [*debug*](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) your programs. For example by using a [*debugger*](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) to step through the code statement by statement while monitoring variables and their values. – Some programmer dude Aug 02 '22 at 10:05
  • 3
    Also, when it comes to things like lists I always recommend pencil and paper. While debugging, draw the nodes and all pointers on paper (for example squares for nodes and other variables, pointers for arrows). Erase and redraw arrows when their corresponding pointer is changing in the program. Does your drawing make sense? – Some programmer dude Aug 02 '22 at 10:07
  • 2
    Your task well be easier if you do not program in main, only slit it into functions. – 0___________ Aug 02 '22 at 10:10
  • 1
    Btw, you have swapped the lines: `printf("%s", current->string);` and `current = current->next = node;`. Printing first will print the previous line instead of the one you just read. Also, the printing should be done after the closing `}` of the `else`, like [this](https://godbolt.org/z/a7Gf5vx1h) – Ted Lyngmo Aug 02 '22 at 10:19
  • ... or [a little more organized](https://godbolt.org/z/h9vK6WW8G). Do you have the same problem if you try that? – Ted Lyngmo Aug 02 '22 at 10:39
  • @TedLyngmo Every line will have a `\n`. You should replace it with `\0` I guess... – Zakk Aug 02 '22 at 10:54
  • @Zakk I don't think that's a problem OP is fighting right now. OP even uses `"%s"` instead of `"%s\n"` to print the strings so he/she seems to be aware of the fact that `fgets` puts the newline in the buffer too. – Ted Lyngmo Aug 02 '22 at 10:58
  • @TedLyngmo Why don't you post the code you linked to as an answer? – Zakk Aug 02 '22 at 11:00
  • @Zakk Oh well, I'm not 100% sure this is what OP asked about but I put it up. Hopefully it'll help some. – Ted Lyngmo Aug 02 '22 at 11:32
  • @TedLyngmo Hi sir.. Thank you for this. I can run this code, now I need to sort the contents of file in alphabetical order. I am stuck there. Can I know how please? – user_191998 Aug 12 '22 at 11:01
  • 1
    @user_191998 Normally, you should separate your questions and only ask one specific thing per question. Since my first answer answered your question, the thing people usually do is to [upvote and/or accept](https://stackoverflow.com/help/someone-answers) the answer, then ask a new question if there are more things you need help with. Anyway, I did add information to my answer for how to make it sorted alphabetically. – Ted Lyngmo Aug 12 '22 at 12:31
  • My file consists of both integer and character datatype, so the above code will print the strings. So can I use "atoi" in switch statements to convert the data type? Can I know how to do it so? With code. @TedLyngmo – user_191998 Aug 12 '22 at 12:40
  • 1
    @user_191998 I'm done with this question. I've answered your original question and then I answered what should have been a separate question for how to get them sorted alphabetically. I also informed you about that it's adviceable to ask a new separate question when you have something else that you want to know, yet you haven't accepted my answer and/or asked a new separate question but continue to add more requirements to this question. – Ted Lyngmo Aug 12 '22 at 12:46
  • @TedLyngmo Please check this question https://stackoverflow.com/questions/73386711/i-need-to-convert-from-characterstring-to-integer-and-print-it – user_191998 Aug 17 '22 at 10:20

1 Answers1

1

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;
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108