metraon
metraon

Reputation: 1259

Append a string from fscanf to linked list in C

I want to read a file and put each words in a linked list. When I read the file, the linked list have the good number of nodes but all the node are equal to the last word.

An example, if my text file is :

Hello good sir

My linked list will look like this :

[sir,sir,sir]

And should be like this :

[Hello, good, sir]

My main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

typedef struct NodeTag {
  char *data;
  struct NodeTag *next;
} Node;

Node *Node_create();

typedef struct ListTag {
  struct NodeTag *first;
} List;

List *List_create();
void List_append(List *list, char *str);
void List_print(List *list);

int main(void) {
  char word[100];
  FILE *file = fopen("file.txt", "r");

  if(file == NULL) {
    printf("error in opening file\n");
    return 1;
  }

  List *l = List_create();

  while(fscanf(file, "%s", word) == 1){
    List_append(l, word);
  }
  return 0;
}

Here are my functions. I removed the destroy and free functions to make it more clear.

Node *Node_create() {
  Node *node = malloc(sizeof(Node));
  assert(node != NULL);

  node->data = "";
  node->next = NULL;

  return node;
}

List *List_create() {
  List *list = malloc(sizeof(List));
  assert(list != NULL);

  Node *node = Node_create();
  list->first = node;

  return list;
}

void List_append(List *list, char *str) {
  assert(list != NULL);
  assert(str != NULL);

  Node *node = list->first;
  while (node->next != NULL) {
  node = node->next;
  }

  node->data = str;
  node->next = Node_create();
}

void List_print(List *list) {
  assert(list != NULL);

  printf("[");
  Node *node = list->first;
  while (node->next != NULL) {
    printf("%s", node->data);
    node = node->next;
    if (node->next != NULL) {
      printf(", ");
    }
  }
  printf("]\n");
}

If I do something like this, it will work properly. So I guess I append only the pointer of word so its pointing to the same place again and again ?

    List_append(l, "test1");
    List_append(l, "test2");

Output :

   [test1, test2]

Upvotes: 2

Views: 835

Answers (2)

dbush
dbush

Reputation: 224437

Inside of List_append, you're doing this:

node->data = str;

That saves a pointer to the data that was passed in as str. You call List_append(l, word) in main, meaning you're passing it the same piece of memory every time, so each list member points to the same piece of memory.

You instead need to do this in List_append:

node->data = strdup(str);

This copies the string into a newly allocated buffer. Just be sure to free it when you clean up.

Upvotes: 3

templatetypedef
templatetypedef

Reputation: 373012

Notice that in main, you have one buffer storing strings:

char word[100];

You pass word as a parameter to your List_append method, during which you write

node->data = str;

This means that all of the nodes are pointing back to the word buffer in main for their string, so all of them will display the same string.

To fix this, you need to duplicate the buffer somewhere. I'd recommend doing something like this:

node->data = strdup(str);

There may be other issues in the code, but this is certainly something that you'll need to fix before you move on. Try updating this and see if it resolves your issue. As @Sean Bright points out, it seems like you're also overwriting the wrong string pointers when you do an append, so you'll probably need to fix that as well.

Hope this helps!

Upvotes: 4

Related Questions