Thread: extract words from a text file and save them to a linked list

  1. #1
    Registered User
    Join Date
    Dec 2011
    Posts
    7

    extract words from a text file and save them to a linked list

    i have a problem in my code. I want to read lines from a text file and split the line into words and save each word to a linked list. In main method first i am calling the init_list function to init the list, next i am calling the open_file function to open a file and reading line by line until i get to the end of file. Each time i read a line i am calling stringtoken function to split the line into words. Now in stringtoken function have a printf to print each word and works fine , is printing the word that has to be printed, after that i am calling the list_add function to add the words in a linked list. When all these are done in main method i am calling function print_list to print the elements of the list but is printing garbage. I can not understand why print_list is printing garbage. here is my code:
    Code:
    #include <stdlib.h> 
    #include <string.h> 
    #include <time.h> 
    #include <stdio.h>
    
    
    struct list {
      char  *val;
      struct list *next;
    };
    struct list *root;    
    struct list *head;
    FILE *f;
    int node_counter=0;
    
    
    int main(char *argv[],int argc){
     int i;
     
     i=init_list();
     open_file();
     print_list(head);
     return(0);
     
    }  
    
    
    int init_list(){
      node_counter=0;
      root=(struct list *)malloc(sizeof(struct list));
      if(root==NULL ){
        printf("Init list failed\n");
        return(1);
      }
        root->next=NULL;
        
        return(0);
      
    }
    //insert a node at the end of the list
    int list_add(char *string){
      struct list *curr;
      curr = (struct list *)malloc(sizeof(struct list));
      if(curr==NULL){
        printf("Adding to a list failed\n");
        return(1);
      }
      
      if(node_counter==0)
        head=curr;
    
    
      curr->val=string;
      root->next=curr;
      curr->next=NULL;
      root=curr;
      node_counter++;
      return(0);
    }
    void print_list (struct list * head) {
        struct list * ptr =head;
        while(ptr!=NULL){
            printf("%s ", ptr->val);
            ptr=ptr->next;
        }
        printf("\n");
    }
    int stringtoken (char str[])
    {
      char * pch;
      pch = strtok (str," ,.-");
      while (pch != NULL)
      {
        print_list(head);
        list_add(pch);
        pch = strtok (NULL, " ,.-");
      }
      return 0;
    }
    open_file(){
      char fname[60];
      char line [ 128 ];
      printf("Give the name of the file\n");
      scanf("%s",fname);
    
    
      f=fopen(fname,"r");
         if ( f!= NULL )
       {
          while ( fgets ( line, sizeof line, f ) != NULL ) /* read a line */
          {
        stringtoken(line);    //split line to tokens
          }
          fclose ( f );
       }
       else
       {
          printf("ERROR OPENING THE FILE");
          return(1);
       }
       return 0;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > curr->val=string;
    You're just pointing at string fragments in a buffer you don't own.
    So when openfile returns, the line buffer goes out of scope, and all your pointers into it are junk.

    You need to malloc space for the string and make a copy of it.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2011
    Posts
    7
    I malloc space for the line buffer in open file and now is printing me the last character of the text file, sometimes with a couple of spaces as the elements of the list.
    Where i must make a copy of the string?

  4. #4
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by gioullis View Post
    I malloc space for the line buffer in open file and now is printing me the last character of the text file, sometimes with a couple of spaces as the elements of the list.
    Where i must make a copy of the string?
    As explained... what you're doing is setting all your pointers to the string buffer, this does not make a copy of the string so you run into two problems... 1) all your pointers end up pointing to the same place, 2) when the function returns the data buffer is destroyed invalidating your buffers.

    You have some choices here...

    1) If your library supports the strdup() function ... use it to copy the strings out of the buffer and set pointers to them in your structs.
    2) Use malloc() then strcpy() to copy the strings out of the buffer.
    3) Load the whole file in one pass, use strtok() on the data in-place to get pointers for your structs.

    Methods 1 and 2 will require you to free() every string and every struct individually which is ok.
    Method 3 allows you to free() your list structs then dump the text in a single free() call, which is a bit more efficient.
    Memory usage is about the same no matter which way you choose.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    The line of code I quoted.

    You alloc each node, but you also need to alloc each string as well.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Dec 2011
    Posts
    7
    i have changed my list_add function like this
    Code:
    int list_add(char *string){
      struct list *curr;
      char *str;
      curr = (struct list *)malloc(sizeof(struct list));
      str= (char *)malloc(60*sizeof(char));
      strcpy(str,string);
      if(curr==NULL){
        printf("Adding to a list failed\n");
        return(1);
      }
      
      if(node_counter==0)
        head=curr;
    
    
       curr->val=str;
      //strcpy(curr->cstr.val,string);
      root->next=curr;
      curr->next=NULL;
      root=curr;
      node_counter++;
      return(0);
    }
    .
    Now is printing me the words but also sometimes print spaces between three or four characters.

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by gioullis View Post
    Now is printing me the words but also sometimes print spaces between three or four characters.
    In your strtok() code you should add a couple of more things... \n \l \0 for starts.

    Print your strings between markers as you extract them to be sure there's no strays in there...
    Code:
    printf("|%s|\n", string);

  8. #8
    Registered User
    Join Date
    Dec 2011
    Posts
    7
    i used fscanf instead of strtok and problem solved. Anyway thanks guys for the help

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 05-25-2011, 05:54 PM
  2. Reading Text file in Linked list!
    By satty in forum C Programming
    Replies: 20
    Last Post: 07-29-2010, 08:48 AM
  3. Replies: 4
    Last Post: 10-19-2009, 12:10 AM
  4. Replies: 11
    Last Post: 04-17-2008, 02:29 AM
  5. print a text-file in linked list
    By tidemann in forum C Programming
    Replies: 10
    Last Post: 09-19-2006, 05:22 AM

Tags for this Thread