Link to home
Start Free TrialLog in
Avatar of roccogalati
roccogalati

asked on

How to read a text file and store it into a Linked List

Hi to all!

I need to read all the values from a text file like this:

[code]
100 String1
256 String2
586 String3
...
and so on...
[/code]

and to store them into a Linked List or a BST.
What do you think it's better? Linked List or BST?
(i need it for a TCP server application...)

For the moment, i thought to use a Linked List, so i started with this structure:

struct object_list {
char name[MAX_LINE];
int code;
};

struct object_list list[MAX_LINE];


and i read the file with this code:

void read_text_file(){

   FILE * pFile;
   char buffer [100];
   int code;
   char name[MAX_LINE];
   struct object_list *p;
   
   
   pFile = fopen ("text.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( ! feof (pFile) )
     {
       fgets (buffer , 100 , pFile);
         sscanf(buffer,"%d %s \n", &code, name);
         printf("%d + %s\n", code, name);
        
     }
     fclose (pFile);
   }
   return 0;

}

I'd like to use malloc to allocate new nodes, but what can i do in order to associate the nodes with name and code?
I'd like to let connected clients to search a name by simply entering the code they want... (do you think a BST it's better in this case?)

Can u help me, please?
i'm not able to write a nice code to populate the list by reading the file :-(

Thanks for your help, and sorry for my English.
Avatar of Infinity08
Infinity08
Flag of Belgium image

>> What do you think it's better? Linked List or BST?

Depends on what you want to do with the data.


>> so i started with this structure:

That's not a linked list - it's a simple array.


>> I'd like to let connected clients to search a name by simply entering the code they want... (do you think a BST it's better in this case?)

A BST would be faster to search in than a linked list. So, it's probably the better choice of the two.


>> i'm not able to write a nice code to populate the list by reading the file :-(

Before writing code, you should first decide what you want to use ;)


Take a look here for more info on BST's (including the algorithm) :

        http://en.wikipedia.org/wiki/Binary_search_tree
Avatar of roccogalati
roccogalati

ASKER

yep, i already read some infos about BST...

i think BST it's a more elegant method than Linked List, but i realy need it?

i just need to let connect clients to do search by entering the code associated with a name...

may be i can just use a Linked List... what do u think it's better?

it's better if I use BST?
 
If you want to be able to search fast, then a BST is better than a linked list (It's not for nothing that it's called a Binary Search Tree). If you want to spend less time inserting elements, then a linked list is better than a BST.

How many entries do you plan to store in the data structure ?
i don't know exactly the amount of data... but i'm thinking this:

it's the server which have to load and insert the elements and the clients have simply to read or search for them...

so i think it's better to use BST to make the reading and the searching how much fast it is possible...

the server have all the time to load the elements in local... so i think it's better to improve reading operations...

so i decide to use BST...

but how write an efficient code which can read from the text line by line and store the values in the tree?

i store code and name like this:

###
  fgets (buffer , 100 , pFile);
         sscanf(buffer,"%d %s \n", &code, name);
         printf("%d + %s\n", code, name);
###

>> but how write an efficient code which can read from the text line by line and store the values in the tree?

First of all, implement the tree (on the wiki page I posted, there's also some C code if you're interested). Make sure you have a function to insert an item into the tree, as well as a function to search for a code in the tree and return the item that corresponds to it (again see the wiki page I posted).

Once you've got the code for the BST working, you can write the code that reads the file line by line (just like the code you posted), and then calls the BST insert function to insert them in the BST.
but i have to use the code as the key ?

and what i have to do in order to associate the code with the name?

>> but i have to use the code as the key ?

That would be easiest, yes.


>> and what i have to do in order to associate the code with the name?

You can use a struct to group data. Something like :

        typedef struct Item {
            int code;
            char name[MAX_LINE];
        } Item;

And then make a BST of these structs.
Mmh... at the end i decided to use a simply Linked List...


do u think it can work?

i did this:

struct object_list {
char name[MAX_LINE];
int code;
};


void add_value(int code, char *name){

struct object_list *p;

strcpy(p->name, name);
p->code = code;

}

struct object_list *search(char *name){

struct object_list *p;

while( p != NULL){

if (strcmp(name, p->name) == 0)
    return p;

}

}


i add the values from the file with this:

while ( ! feof (pFile) )
     {
       fgets (buffer , 100 , pFile);
         sscanf(buffer,"%d %s \n", &code, name);
         printf("%d + %s\n", code, name);
         add_value(code, name);
     }



do you think it can work well?
ASKER CERTIFIED SOLUTION
Avatar of Infinity08
Infinity08
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
because i thought that i only have to store some values... so i can just use a simply list wich allow me to insert and search for values...

...


and what i wrote can't work in any way?
>> because i thought that i only have to store some values...

I asked you about that earlier ... remember ? ;)


>> and what i wrote can't work in any way?

Well, it won't work for several reasons :

1) you didn't implement a linked list
2) you're dereferencing invalid pointers (pointers pointing to some invalid/unallocated memory location)
3) your add_value and search functions are incomplete

I really suggest you take a look at the wiki I posted about linked lists. Get familiar with how they are constructed and how they work, and then take a look at the pseudo code and C code there to get an idea of how to implement it.
I've got the theory, may be...

so i think i have to use *next it i want to go from a node to another one...

so, i think i can simply add the values by doing:

struct object_list *p;

...

fgets (buffer , 100 , pFile);
         sscanf(buffer,"%d %s \n", &code, name);
         printf("%d + %s\n", code, name);
         strcpy(p->name, name);
         p->code = code;


and then i have to use *next point if i want to search for a value?

is not correct... i need to add each new node at the tail of the list...
because i need to have all the values in the same order written in the text file...


so i need an head pointer...
Now is it correct?


struct node {
char name[MAX_LINE];
int code;
struct node *next;
};
 
 
...
...
 
 
 
void add_values(char *name, int code){
 
struct node *root, *conductor;
root = malloc( sizeof(struct node));
root->next = 0;
root->code = code;
strcpy(root->name, name);
if(conductor != 0){
  while ( conductor->next != 0)
        {
            conductor = conductor->next;
        }
		}
    
}

Open in new window

It doesn't work very well...

It prints me only conductor->code and not also conductor->name



void read_file(){
 
   FILE * pFile;
   char buffer [100];
   int code;
   char name[MAX_LINE];
 
   struct node *root, *conductor;
   root = malloc( sizeof(struct node));
   root->next = 0;
   
   pFile = fopen ("text.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( ! feof (pFile) )
     {
       fgets (buffer , 100 , pFile);
	   sscanf(buffer,"%d %s \n", &code, name);
	   printf("%d + %s\n", code, name);
	   root->code = code;
       strcpy(root->name, name);
if(conductor != 0){
  while ( conductor->next != 0)
        {
            conductor = conductor->next;
        }
		}
		
		 }
     fclose (pFile);
    
    /* for print the list */
    conductor = root;
    if ( conductor != 0 ) { /* Makes sure there is a place to start */
    while ( conductor->next != 0 ) {
        printf( "Lista: %d\n%s", conductor->code, conductor->name );
        conductor = conductor->next;
    }
    printf( "List: %d\n%s", conductor->code, conductor->name );
}
   }
   
 
}

Open in new window

Finally i was able to write some correct code...

Now, it can add values from the file and print them...

it works well...

the only problem it's that i need to print the list in the reverse order...

what can i do?

thanks to all...

 
struct llist *  /* return type */
new_list() {   /* function name */
  struct llist *lst;
  
  lst = (struct llist *) malloc(sizeof(struct llist));
 
  /* malloc returns 0 on error */
  if (lst == NULL) {
    fprintf(stderr, "new_list() : malloc error");
    return NULL;
  }
 
  /* initialize the list size and the list head */
  lst->head = 0;
  lst->size = 0;
  return lst;
}
 
 
struct lnode *
new_node(char *item, int code) {
  struct lnode *node;
  node = (struct lnode *) malloc (sizeof (struct lnode));
  if (node == NULL) {
    fprintf(stderr, "new_node() : malloc error");
    return NULL;
  }
  strcpy(node->item, item);
  node->code = code;
  node->next = 0;
  return node;
}  
 
 
 
int
l_insert(struct llist *ls, char *item, int code) {
  struct lnode *node;
  /* get a new node */
  node = new_node(item, code);
  if (node == NULL) return 0;
  
  /* insert the node at the head of the list */
  node->next = ls->head;
  ls->head = node;  
  (ls->size)++;
  printf("Lista: %d, %s\n", node->code, node->item);
  
  
  
  return 1;
}
 
void print( struct llist *ls){
 
struct lnode *node;
node->next = ls->head;
printf("STAMPA\n");
while(node != NULL){
printf("STAMPA: %s, %d\n", node->item, node->code);
node = node->next;
}
}
 
 
int main(void) {
 
   struct llist *list;
   list = new_list();
  
   FILE * pFile;
   char buffer [100];
   int code;
   char name[1000];
 
      
   pFile = fopen ("cancelleria.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( ! feof (pFile) )
     {
       fgets (buffer , 100 , pFile);
	   sscanf(buffer,"%d %s \n", &code, name);
	   printf("%d + %s\n", code, name);
	   l_insert(list,  name, code);
	   }
	   fclose (pFile);
      }
   
    print(list);
	
return 0;
}

Open in new window

Sorry for the delay :) Nice job on the linked list implementation.

There's just a small problem in the print function :

        struct lnode *node;
        node->next = ls->head;

You're dereferencing node before it has been initialized with a correct address. You probably meant :

        struct lnode *node;
        node = ls->head;



>> the only problem it's that i need to print the list in the reverse order...

First of all, I assume you know that you're still inserting items at the front of the linked list ?
There is an easy way to add items at the back of a linked list, and that's by keeping a pointer to the last element in the linked list (you can place it in your llist struct).

If you need to be able to traverse a linked list backwards, there are two approaches :

1) if the list is very small (only a few elements), you can use a recursive method to traverse the tree to the end, and when the recursive function calls "unwind", you print the items.

2) a more robust solution is to have a doubly linked list. Ie. instead of having just a next pointer in each node, you also have a prev pointer in each node that points to the previous item in the linked list.
i think it's better to use a doubly linked list...

but i have to change all my implementation or i simply need to use a *prev pointer like this?

and i have to add also a *tail pointer or i can just use my head pointer?


struct lnode {
  struct lnode *next;
  struct lnode *prev;
  char item[1000];
  int code;
};  

Open in new window

>> but i have to change all my implementation or i simply need to use a *prev pointer like this?

Not all of it. When you do an insert, you have to make sure to set the prev pointer to point to the previous node.


>> and i have to add also a *tail pointer or i can just use my head pointer?

A tail pointer would make it easier to add nodes to the end of the linked list (the alternative is to traverse the whole list until you reach the end).
if i use this recursive function to reverse the order, i get a bus error...
void print_reverse( struct llist* list )
{
    struct lnode *node;
    node = list->head;
    if ( list != 0 )
    {
        print_reverse( node->next );
        printf("STAMPA: %s, %d\n", node->item, node->code);
    }
}

Open in new window

Try this instead :


void print_reverse(struct lnode *node) {
    if (node != 0) {
        print_reverse(node->next);
        printf("STAMPA: %s, %d\n", node->item, node->code);
    }
}
 
/* called like this : */
print_reverse(list->head);

Open in new window

Be careful to only use this for small linked lists though ... The stack has a limited size, which limits the recursion depth.
The amount of data with this kind of solution is something near O(n)... and it's too large i think...

is it correct if i try to implement the doubly linked list like this ?
int
l_insert(struct llist *ls, char *item, int code) {
  struct lnode *node;
  /* get a new node */
  node = new_node(item, code);
  if (node == NULL) return 0;
  struct lnode *curr, *prev;
  curr = ls->head;
  prev = NULL;
  
  while ( node != NULL){
  
  prev = curr;
  curr = curr->next;
  
  }
  
  node->next = curr;
  node->prev = prev;
  
  
  
  /* insert the node at the head of the list */
  //node->next = ls->head;
  //ls->head = node;  
  
  (ls->size)++;
  printf("Lista: %d, %s\n", node->code, node->item);
  
  
  
  return 1;
}

Open in new window

>>   while ( node != NULL){

You probably meant :

        while ( curr != NULL){


>>   node->next = curr;
>>   node->prev = prev;

You also have to update the next pointer of the previous node :

        prev->next = node;


Now, your code is inserting at the end of the linked list. Note that that would have been a lot easier if you had a pointer pointing to the last element in the node - inserting would then just be something like :

        tail->next = node;
        node->prev = tail;
        node->next = 0;
I updated also the previous node...

so now it seems to work well... thanks a lot!

the problem now it with the printing function, i modified it with a for()... i start to read nodes from the head...
but it prints me only the first printf and then it do nothing else...
i think it never enter in the for...





void print( struct llist *ls){
 
struct lnode *node;
printf("PRINT\n");
for(node = ls->head; node != NULL; node->next){
printf("STAMPA: %s, %d\n", node->item, node->code);
 
}
 
}
 
and call it with: 
print(list);

Open in new window

>> for(node = ls->head; node != NULL; node->next){

Use this instead :

        for(node = ls->head; node != NULL; node = node->next){

(see the difference ?)
yep, i can get the "little" difference :)
but it still doesn't work... :-(

theorically, for me, it seems to be ok... but in the practice it doesn't work...

the whole code is this:
struct lnode {
  struct lnode *next;
  struct lnode *prev;
  char item[1000];
  int code;
};  /* <---- note the semicolon */
 
/* The definition of what a llist (linked list) is.  */
struct llist {
  struct lnode *head;
  struct lnode *tail; /* i'm not using it */
  int size;
};
 
 
 
int l_insert(struct llist *ls, char *item, int code) {
  struct lnode *node;
  /* get a new node */
  node = new_node(item, code);
  if (node == NULL) return 0;
  struct lnode *curr, *prev;
  curr = ls->head;
  prev = NULL;
  
  while ( curr != NULL){
  
  prev = curr;
  curr = curr->next;
  prev->next = node;
  
  }
  
  node->next = curr;
  node->prev = prev;
  
	  
  (ls->size)++;
  printf("Lista: %d, %s\n", node->code, node->item);
  
  
  
  return 1;
}
 
 
void print( struct llist *ls){
 
struct lnode *node;
printf("STAMPA\n");
for(node = ls->head; node != NULL; node = node->next){
printf("STAMPA: %s, %d\n", node->item, node->code);
 
}
 
}

Open in new window

You misplaced this line in the insert function :

  prev->next = node;

It should not be inside the while loop. Look after which two lines I placed it ...
i did like u said... i updated the previous pointer after the while cicle...
but it gives me bus error (i'm on a mac)

Can you show your entire code (all of it) ?
Here it is:

#include <stdio.h>
 
int l_insert(struct llist *ls, char *item, int code) {
  struct lnode *node;
  /* get a new node */
  node = new_node(item, code);
  if (node == NULL) return 0;
  struct lnode *curr, *prev;
  curr = ls->head;
  prev = NULL;
  
  while ( curr != NULL ){
  
  prev = curr;
  curr = curr->next;
 
  }
  
  
  node->next = curr;
  node->prev = prev;
  prev->next = node;
  
  
	  
  (ls->size)++;
  printf("Lista: %d, %s\n", node->code, node->item);
  
  
  return 1;
}
 
void print( struct llist *ls){
 
struct lnode *node;
printf("STAMPA\n");
for(node = ls->head; node != NULL; node = node->next){
printf("STAMPA: %s, %d\n", node->item, node->code);
 
}
 
}
 
/* i'm not using it */
void print_reverse(struct lnode *node) {
    if (node != 0) {
        print_reverse(node->next);
        printf("STAMPA: %s, %d\n", node->item, node->code);
    }
}
 
/* -----------------------------------------------------------------
 * main()
 * This test code is admittedly bogus.
 * ----------------------------------------------------------------- */
int main(void) {
 
   struct llist *list;
   list = new_list();
  
   FILE * pFile;
   char buffer [100];
   int code;
   char name[1000];
 
      
   pFile = fopen ("text.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( ! feof (pFile) )
     {
       fgets (buffer , 100 , pFile);
	   sscanf(buffer,"%d %s \n", &code, name);
	   printf("%d + %s\n", code, name);
	   l_insert(list, name, code);
	   }
	   fclose (pFile);
      }
   
    print(list);
	
return 0;
}

Open in new window

Sorry...
the entire code is this:

#include <stdio.h>
#include <stdlib.h>
 
struct lnode {
  struct lnode *next;
  struct lnode *prev;
  char item[1000];
  int code;
}; 
 
struct llist {
  struct lnode *head;
  struct lnode *tail;
  int size;
};
 
struct llist *  /* return type */
new_list() {   /* function name */
  struct llist *lst;
  
  lst = (struct llist *) malloc(sizeof(struct llist));
 
  /* malloc returns 0 on error */
  if (lst == NULL) {
    fprintf(stderr, "new_list() : malloc error");
    return NULL;
  }
 
  /* initialize the list size and the list head */
  lst->head = 0;
  lst->size = 0;
  lst->tail = 0; / I'm not using it for the moment */
  return lst;
}
 
/* -----------------------------------------------------------------
 * struct new_node * new_node(void *item)
 *
 * Function that works like a constructor for lnodes.
 * Takes a void pointer and returns a pointer to a struct lnode.
 * ----------------------------------------------------------------- */
struct lnode *
new_node(char *item, int code) {
  struct lnode *node;
  node = (struct lnode *) malloc (sizeof (struct lnode));
  if (node == NULL) {
    fprintf(stderr, "new_node() : malloc error");
    return NULL;
  }
  strcpy(node->item, item);
  node->code = code;
  node->next = 0;
  node->prev = 0;
  return node;
}  
 
 
/* -----------------------------------------------------------------
 * int l_insert(struct llist *ls, void *item)
 *
 * Insert function for a list.  Takes a pointer 'ls' to the list on 
 * which we want to insert 'item'.
 * Returns 0 on error, 1 otherwise.
 * ----------------------------------------------------------------- */
int l_insert(struct llist *ls, char *item, int code) {
  struct lnode *node;
  /* get a new node */
  node = new_node(item, code);
  if (node == NULL) return 0;
  struct lnode *curr, *prev;
  curr = ls->head;
  prev = NULL;
  
  while ( curr != NULL ){
  
  prev = curr;
  curr = curr->next;
 
  }
  
  
  node->next = curr;
  node->prev = prev;
  prev->next = node;
  
	  
  (ls->size)++;
  printf("Lista: %d, %s\n", node->code, node->item);
  
  
  return 1;
}
 
void print( struct llist *ls){
 
struct lnode *node;
printf("STAMPA\n");
for(node = ls->head; node != NULL; node = node->next){
printf("STAMPA: %s, %d\n", node->item, node->code);
 
}
 
}
 
 
void print_reverse(struct lnode *node) {
    if (node != 0) {
        print_reverse(node->next);
        printf("STAMPA: %s, %d\n", node->item, node->code);
    }
}
 
/* -----------------------------------------------------------------
 * main()
 * This test code is admittedly bogus.
 * ----------------------------------------------------------------- */
int main(void) {
 
   struct llist *list;
   list = new_list();
  
   FILE * pFile;
   char buffer [100];
   int code;
   char name[1000];
 
      
   pFile = fopen ("cancelleria.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( ! feof (pFile) )
     {
       fgets (buffer , 100 , pFile);
	   sscanf(buffer,"%d %s \n", &code, name);
	   printf("%d + %s\n", code, name);
	   l_insert(list, name, code);
	   }
	   fclose (pFile);
      }
   
    print(list);
	
return 0;
}

Open in new window

code.txt
In the insert function :

>>   prev->next = node;

You will have to protect that line, because if prev is NULL, this will crash. So, only execute it if prev is not NULL.

The rest looks good.
like this?
 node->next = curr;
  node->prev = prev;
  
  if ( prev != NULL ){
  
  prev->next = node;
  
  }
 
/* this time doesn't give me "bus error", but it doesn't print anything...

Open in new window

>> like this?

Yes.


>> but it doesn't print anything...

Not even these :

        printf("%d + %s\n", code, name);

? If not, then check the file - does it contain valid data ?
yep, it contains valid data, infat it printf the values if i use printf to print code and name...

but it doesn't print the values stored in the list...


i'm trying to implement another list... because i'm not able to understand why this doesn't work properly... :(

i think code it's good... so... why doesn't work...
Does it do this printf inside the insert function ?

         printf("Lista: %d, %s\n", node->code, node->item);
yep, it works properly...

so... we can be sure that it stores correctly the values in the list...

the problem is in print function, it never enters in the for cicle... and if it enters... it isn't able to read the values...

mmmh...
void print( struct llist *ls){
 
struct lnode *node;
printf("STAMPA\n");
for(node = ls->head; node != NULL; node = node->next){
printf("STAMPA: %s, %d\n", node->item, node->code);
 
}

Open in new window

That's because the insert function doesn't handle the case where ls->head is NULL ;)
Oh, and btw, you have all those malloc's. You should have the corresponding free's too. Ie. write a function that properly deletes the list (free-ing all nodes).
i wrote another doubly list code... more simple...

it looks like to work well...

i have only a problem... with the reading from the text file...

it store twice the last line in the file...

for example, if file contains:

100 string1
200 string2
256 string 3

it displays:

100 string1
200 string2
256 string3
256 string3

why? can u explain me why this happen, please?


(-> here is the code)
Node *insertafter(Node *after, int code, char *name)
{
  Node* n;
  n = (Node *) malloc (sizeof(Node));
  n->code = code;
  strcpy(n->name, name);
 
  //incase header node is not created
  if (!after)
  {
    n->prev = NULL;
    n->next = NULL;
    return n;
  }
 
  n->prev = after;
  n->next = after->next;
 
  if (after->next)
  {
    after->next->prev = n;
  }
  after->next = n;
  return n;
}
 
int printlist(Node *h)
{
  Node* t = h;
 
  //check we have any nodes before the node given
  while(t && t->prev)
  {
    t = t->prev;
  }
 
  while(t)
  {
    printf(" %d <-> %s\n", t->code, t->name);
    t = t->next;
  }
  printf(" FINE\n");
  return 0;
}
 
 
 
Node *searchlist(Node *h, char *name)
{
  Node* n = h;
  Node* after = h;
  Node* before = h->prev;
  
  //search all nodes after n (if any)
  while(after)
  {
    if (strcmp(after->name, name) == 0)
    {
      printf("Primo loop: %d\n", after->code);
	  return after;
    }
    after = after->next;
  }
 
  //search all nodes before n (if any)
  while(before)
  {
    if (strcmp(before->name, name) == 0)
    {
      printf("Primo loop: %d\n", before->code);
	  return n;
    }
    before = before->prev;
  }
 
  return NULL;
}
 
 
int main(void)
{
  
  Node *n = NULL;
  Node *h = createlist();
 
 
 FILE * pFile;
   char buffer [100];
   int code;
   char name[1000];
 
      
   pFile = fopen ("cancelleria.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( ! feof (pFile) )
     {
       fgets (buffer , 100 , pFile);
	   sscanf(buffer,"%d %s \n", &code, name);
	   h = insertafter(h, code, name);
	   searchlist(h, name); /* just for testing if search works */
	   }
	   fclose (pFile);
      }
 
 printlist(h);
  
 
  return 0;
}

Open in new window

>> it store twice the last line in the file...

That's most likely because there's an empty line at the end of the file. Is there ?

You can protect against that by checking for 0-length strings (read by fgets) and also by checking the return value of sscanf (it has to be 2, otherwise the read failed).
i solved with this:

i read the file until i get a string NULL...

now it works fine...


last question... i can't know, before reading the text file, how long is each line...
so now i choose to read 100 chars, but... there is another efficient way to read a file line by line?




if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( fgets (buffer , 100 , pFile) != NULL )
     {       
	   sscanf(buffer,"%d %s \n", &code, name);
	   h = insertafter(h, code, name);
	   searchlist(h, name1);
	   }
	   fclose (pFile);
      }

Open in new window

another problem...

the search function works well if i call it in the while cicle... but it doesn't work out of it...

it seems strange... because the printing function works well at the contrary...


char name1[10] = "string";
 
#### OK ####
 
pFile = fopen ("cancelleria.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
    {
     while ( fgets (buffer , 100 , pFile) != NULL )
     {       
	   sscanf(buffer,"%d %s \n", &code, name);
	   h = insertafter(h, code, name);
	   searchlist(h, name1);
      }
	   fclose (pFile);
      }
 
 
#### DOESN'T WORK ####
 
pFile = fopen ("cancelleria.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( fgets (buffer , 100 , pFile) != NULL )
     {       
	   sscanf(buffer,"%d %s \n", &code, name);
	   h = insertafter(h, code, name);
	   }
	   fclose (pFile);
      }
 searchlist(h, name1); 
 
########
 
 
the entire code:
 
#include <stdio.h>
 
typedef struct Node Node;
 
struct Node
{
  char* name[1000]; 
  int code;
  Node* next; 
  Node* prev; 
};
 
 
 
Node *createlist()
{
  return NULL;
}
//insert before a known node and return the inserted node
 
//insert after a known node and return the inserted node
Node *insertafter(Node *after, int code, char *name)
{
  Node* n;
  n = (Node *) malloc (sizeof(Node));
  n->code = code;
  strcpy(n->name, name);
 
  //incase header node is not created
  if (!after)
  {
    n->prev = NULL;
    n->next = NULL;
    return n;
  }
 
  n->prev = after;
  n->next = after->next;
 
  if (after->next)
  {
    after->next->prev = n;
  }
  after->next = n;
  return n;
}
 
//given any node in list, prints entire list
int printlist(Node *h)
{
  Node* t = h;
 
  //check we have any nodes before the node given
  while(t && t->prev)
  {
    t = t->prev;
  }
 
  while(t)
  {
    printf(" %d <-> %s\n", t->code, t->name);
    t = t->next;
  }
  printf(" FINE\n");
  return 0;
}
 
 
 
void searchlist(Node *h, char *name)
{
  
  Node* after = h;
  
  
  //search all nodes after n (if any)
  while(after)
  {
    if (strcmp(after->name, name) == 0)
    {
      printf("Primo loop: %d\n", after->code);
	  return after;
    }
	after = after->next;
   }
  
  return NULL;
}
 
 
 
 
int main(void)
{
  
  Node *h = createlist();
  
   FILE * pFile;
   char buffer [100];
   int code;
   char name[1000];
   char name1[10] = "matita";
      
   pFile = fopen ("cancelleria.txt" , "r");
   if (pFile == NULL) perror ("Error opening file");
   else
   {
     while ( fgets (buffer , 100 , pFile) != NULL )
     {       
	   sscanf(buffer,"%d %s \n", &code, name);
	   h = insertafter(h, code, name);
	   }
	   fclose (pFile);
      }
 searchlist(h, name1); 
 printlist(h);
  
 
  return 0;
}

Open in new window

Sorry, in the search function, the prototype is this:

Node * searchlist(Node *h, char *name);

and not void...


however, i don't know why if a call the function out of the while cicle, it doesn't work...
>> last question... i can't know, before reading the text file, how long is each line...
>> so now i choose to read 100 chars, but... there is another efficient way to read a file line by line?

There's no standard solution. If you don't need to process lines longer than a certain length, you can just ignore the rest of the line. If you DO need to take into account the whole line, then a way to do that would be to provide a dynamically allocated buffer whose size can be increased (using realloc for example). Multiple fgets's can then be called until the end of the line is met.


>> the search function works well if i call it in the while cicle... but it doesn't work out of it...

The problem you experience is because h points to the last node when you try to search for the string. You'll have to save a pointer to the root node, and use that for your searches.
can't I simply use:

Node *h = createlist();
Node *p = h;


and then:

while(p != NULL)
  {
   
      searchlist(p, name1);
        p = p->next
  }

?


>> can't I simply use:

Sure. But you don't need to call the search in a loop.
it doesn't work with this:


Node *h = createlist();
Node *p = h;
searchlist(p, name1);





it works only in this way:

while ( fgets (buffer , 100 , pFile) != NULL )
     {      
         sscanf(buffer,"%d %s \n", &code, name);
         h = insertafter(h, code, name);
         searchlist(h, name1);
         }
         fclose (pFile);
      }
>> it doesn't work with this:
>> 
>> Node *h = createlist();
>> Node *p = h;
>> searchlist(p, name1);

Well of course ... The list is empty.
Hey, wait a second, why is your createlist returning NULL suddenly ?It wasn't doing that before ... Why did you change that and why did you get rid of the List struct ? That was all good !
i changed all the implementation because it was complex to change that linked list into a doubly one...

so i wrote another list which is doubly... it works well... but i have problems with search function...


At the end... i wrote another linked list and when i want to store the data i go at the end of the list and add the item here...

so i have a list with the order i wanted... without using a doubly list...

i fixed adding, printing and searching...

i think now it works great...

or at least... i hope... i'm going to testing it... :)
>> but i have problems with search function...

As I said : those problems were due to changing the createlist function, and removing the List struct.

I don't know why you keep changing the implementation. The doubly linked list you had earlier worked fine.
Thanks for your Help!
At the end, i realized that the amount of data is not too large... and then a linked list is more simple to manage than a doubly one...

thanks a lot for ur advices! ;)
No problem ... Glad to be of assistance :)