Home > Enterprise >  My token won't let me memorise words in linked list
My token won't let me memorise words in linked list

Time:01-28

I am writing a program that should memorize all the words that begin with 'm' in a linked list. The problem I am having is that when I am trying to read the file line by line, divide the line by words using a token pointer and strtok. Then I insert the token into a linked list but when the text is spread to multiple lines.

void append(struct node **head, char *data) {
    struct node *new_node = (struct node*)malloc(sizeof(struct node));
    new_node->data = data;
    new_node->next = NULL;
 
    struct node *curr_node = *head;
 
    if (*head == NULL) {
        *head = new_node;
        return;
    }
 
    while (curr_node->next != NULL) {
        curr_node = curr_node->next;
    }
 
    curr_node->next = new_node;
}
 

Whit this I add a new node to the end of the list.

int read_file(struct node **head, char *file_name) {
    FILE *in = fopen(file_name, "r");
    if (in == NULL) {
        return 1;
    }
 
    char *dividers = " .,!?;:";
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
 
    while((read = getline(&line, &len, in)) != -1) {
        // printf("%zu: ", read);
        // printf("%s", line);
        char *token = strtok(line, dividers);
        while (token != NULL) {
            if (toupper(token[0]) == 'M') {
                // printf("%s ", token);
                append(head, token);
            }
            token = strtok(NULL, dividers);
        }
    }
    printf("\n");
 
    fclose(in);
    return 0;
}
 

The main:

int main() {
    struct node *head = NULL;
    read_file(&head, "text.txt");
    print_list(head);
    free(head);
    exit(EXIT_SUCCESS);
}

With the input below:

Mimi meme
mountain 
momo mana

The output is:


momo mana
 momo momo mana
 

The whole code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void print_list(struct node *n) {
    while (n != NULL) {
        printf("%s ", n->data);
        n = n->next;
    }
    printf("\n");
}
void free_list(struct node **head) {
    struct node *temp_node;
    while (*head != NULL) {
        temp_node = *head;
        *head = (*head)->next;
        free(temp_node);
    }
}
int read_file(struct node **head, char *file_name) {
    FILE *in = fopen(file_name, "r");
    if (in == NULL) {
        return 1;
    }
 
    char *dividers = " .,!?;:";
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
 
    while((read = getline(&line, &len, in)) != -1) {
        // printf("%zu: ", read);
        // printf("%s", line);
        char *token = strtok(line, dividers);
        while (token != NULL) {
            if (toupper(token[0]) == 'M') {
                // printf("%s ", token);
                append(head, token);
            }
            token = strtok(NULL, dividers);
        }
    }
    printf("\n");
 
    fclose(in);
    return 0;
}
 
int main() {
    struct node *head = NULL;
    read_file(&head, "text.txt");
    print_list(head);
    free(head);
    exit(EXIT_SUCCESS);
}

CodePudding user response:

strtok returns pointers into the input string.

If you store these pointers in your list and then read a new line into the same buffer, the data at the saved addresses may get overwritten with the text from the next line. As noted by Barmar in a comment, if getline calls realloc, the memory may even become invalid.

At the end of the processing, the buffer will contain text from the last line and possibly parts from longer lines and all saved pointers will either point into the same memory range or maybe to invalid memory which results in undefined behavior when you try to use the pointers as strings.

You have to create copies of the strings when/before storing them in the list, e.g. by using strdup (or malloc and strcpy).

  •  Tags:  
  • Related