Solved

Linked list saving

Posted on 2000-04-19
18
197 Views
Last Modified: 2013-12-14

Hi again,

I'm doing a project using linked lists and i am stuck on this bit of code..
here is what i have on a procedure to save the contents of a linked list to a text file.. it doesn't seem to work though.. can u tell me what i could do.
This is only a sample part cos the whole thing is too long..
This function is called at the end of the enter() which stores the info into the linked list..
I don't think any info is getting passed to save() but i can't spot why

Please HELP!!!


/* global declaration */
struct address *start;

void save(void)
{
   register int t;
   struct address *info;
   FILE *fp;

   if ((fp = fopen("mlist.txt","wb"))
           == NULL)
   {
         printf("\n File cannot be        opened");
      exit(1);
   }
   printf("\n Saving file");


   info = start;

   while (info != NULL)
   {
         fwrite(info,sizeof(struct address),1,fp);
      info = info->next;
   }
   fclose (fp);
    menu();
}

0
Comment
Question by:anita177
  • 11
  • 7
18 Comments
 

Author Comment

by:anita177
ID: 2731212
Help
0
 
LVL 22

Accepted Solution

by:
nietod earned 50 total points
ID: 2731377
That is an okay way to write it--not great, but okay.  The only thing is you are writting out the linked list structures completely--including their pointers.  That is okay, but you have to realize that those pointer values may not be valid when the address structure is later read in.  So if you read in this data you must read it into a temporary address structure.  then copy the information in this temporary address structure into the new linked list.  (without copying the pointers!).

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 2731443
so you woudl have to do something like.

void read(void)
{
   address AnAdd; // A temporary address variable.
    FILE *fp;

   if ((fp = fopen("mlist.txt","rb")) == NULL)
   {
       printf("\n File cannot be        opened");
       exit(1); // Note it is is not a good idea to use exit() in C++
             // Fine in C, not C++.
             // You can throw an exception instead.  Like
             // throw int(-1);
     }
    printf("\n Saving file");

     while (true)
     {
         // Read 1 item into AnAdd.
         fread(&AnAdd,sizeof(struct address),1,fp);
        if (feof(fp))  // If end of file was reached,
           break; // Abort.

        // Now add a new item to the list using the infor in
        // AnAdd.  I'm not sure of the details of how to do
        // so in your case.
      }
      fclose (fp);
}

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 2731601
FYI, EE seems to be having problems and I keep loosing my post

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 2731624
Seems to be working now.....

Now I sort of left out how the information read gets added the the list.  (As the comment abouve suggests)  You shoudl have some sort of existing add procedure, right?  You should be able to use that.  Let me know if you can't.

One thing I don't like about this approach is that you are wasting space int eh file by storing those list pointers, which then get ignored when the list is read.  One way around this is to use a design that allows you to write only the address information to the file.  One way to do this would be to define the address information without the list poitners in one structure and then in another structure store the address information and the list pointers, like

struct address
{
   char Name[30];
   char Street[30];
   // etc.  I don't really know what you need to store here.
   // Only don't store a pointer to the next item in the list.
};


struct ListNode
{
   address Add; // The stored address information.
   ListNode *next; // -. next item in the list.
};

So you would create a linked list of ListNodes each of which stores the address data in the "Add" data member.  When it is time to read/write the list you read/write only the "add" data member, i.e. jus tthe address, not the pointers.

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 2731654
A few more things...

>> struct address *info;
In C++, you don't need to use "struct" in front of "address" like you do in C.  You use "struct" only when declaring "address" (just the 1 time).  then after that you don't need it.  so you could have

address *info;

>> register int t;
You don't seem to use "t".  also use of "register" is pretty strngly discouraged except in rare cases.

>>   exit(1)
exit() was fine in C, but not in C++.  when exit() is invoked in C++ the locally stored and global objects are not destroyed.  This can make a potentially bad situation worse.   You should end the procedure properly by returning to the caller.  Perhaps using an error return value so the caller can choose what to do about the problem.   Or you should throw an exception.  Which if uncaught (and you would have to add coode to catch it.) will  end the program much like exit(), but allows destructors to be called.

Finally, the line
>>   menu();
makes me nervious.   Why would you have a menu at the end of the procedre to write the data?  I have seen programs that "work" like that.  At the end of each procedure they call a meny procedure that then calls the next procedure the user chooses, which then also ends in a menu procedure, which then calls..... and so on and so on.

That is not good.  Is that what you've done?
0
 

Author Comment

by:anita177
ID: 2733773

Yeah, I am calling the menu () at the end to re-enter options for the user.. i have tried doing this with loops but it didn't work!.

Thanks for your comments earlier it did make me think.. I'm used to  programming C style so excuse the mistakes.

Anyway i thought you might aswell see the add functions as i still don't know how to incorporate the changes you told me about. (The seperate structure for read/writ operations)


void enter (void)
{
      struct address *info;
   struct address *store(struct address *,struct address *);
   int num,i;
   clrscr();

   printf("\n How many record are to be added : ");
   scanf("%d",&num);
   for (i=0;i<num;i++)
   {
         info = (struct address *) malloc(sizeof(list_entry));
    /*  if(!(info))
      {
            printf("\n Out of memory");
         return;
      } */ this part dosen;t work but i need to validate this*/

      inputs("\nEnter name : ",info->name,20);
      if (!info->name[0]) break;
      inputs("\nEnter street : ",info->street,20);
             inputs("\nEnter city : ",info->city,10);
            inputs("\nEnter state : ",info->state,10);
            inputs("\nEnter zip : ",info->zip,10);

      start = store(info,start);
   }
   save();
   menu();
}

struct address *store(struct address *i,struct address *top)
{
      struct address *old, *p;

   if(last == NULL)
   {
         i->next = NULL;
      i->prev = NULL;
      last = i;
      return i;
   }

   p = top;  /* start at top of list */
   old = NULL;

   while (p)
   {
         if (strcmp(p->name,i->name) <0)
      {
            old = p;
         p = p->next;
      }
      else
      {
            if (p->prev)
         {
               p->prev->next = i;
            i->next = p;
            i->prev = p->prev;
            p->prev = i;
            return top;
         }
            i->next = p;
         i->prev = NULL;
         p->prev = i;
         return i;
      }
   }
   old->next = i;
   i->next = NULL;
   i->prev = old;
   last = i;
   return start;

}

It should store the info sorted in name.
Inputs is just another function to validate the right length has been inputted.
0
 
LVL 22

Expert Comment

by:nietod
ID: 2734088
>> Yeah, I am calling the menu () at the end to
>> re-enter options for the user.. i have tried
>> doing this with loops but it didn't work!.
Sorry, you have to go back to loops.  There are problems with this, perhaps beyond your current level of understanding.  A simple explanation is that this approach will continually use more and more and more memory until eventually you run out an the program crashes.  This is not a problem with a loop.  If you post the loop code, I can probably help you with it.

>> I'm used to  programming C style so
>> excuse the mistakes
And very soon, you will be unable to program in C.  C++'s syntax is a much nicer and hard to give up.  I was just back in C recently and found it impossible to get right.
0
 

Author Comment

by:anita177
ID: 2734112
please help soon, i'm waiting for a reply
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 22

Expert Comment

by:nietod
ID: 2734119
You still haven't shown the definition for the address structure.  That would help--some.

Okay.  Store is the function that adds to the linked list.  ("Add" is a more common name.)

This would be the function you need to call from the read() function.  You would do

void read(void)
{
   address AnAdd; // A temporary address variable.
   FILE *fp;

    if ((fp = fopen("mlist.txt","rb")) == NULL)
    {
       printf("\n File cannot be        opened");
       exit(1); // Note it is is not a good idea to use exit() in C++
       // Fine in C, not C++.
       // You can throw an exception instead.  Like
       // throw int(-1);
    }
    printf("\n Saving file");

    while (true)
    {
        // Read 1 item into AnAdd.
       fread(&AnAdd,sizeof(struct address),1,fp);
       if (feof(fp))  // If end of file was reached,
         break; // Abort.

      struct address *info;
      info = (struct address *) malloc(sizeof(list_entry));
      start = store(info,start);                  
    }
    fclose (fp);
}


That answers the "orignal" question--mostly.  But there are more problems.  Some are C vs C++ things.  Like the fact that you probably should not use malloc() in C++  (with one exception and this isn't it.).  But a nother problem is just the central design.  I don't think you are managing the list correctly, at least not well.   I don't see how you can be setting the end pointers to the list correctly--excepty maybe through the use of global variables, and that would be a bad practice.  Usually you woudl create a struct (or class) for storing the first and last pointers of the list.  Like

struct AddressList
{
   Address *first;
   Address *last;
}

This struct would in essense be the list.  At least in the sense that it provides access to the items in the list.  You would pass this structure around in your program as a way of "passign around" the list itself.  i.e the store() function would be passed a structure like this that would indicate which list the data was to be stored in.  

This is probably going to take a lot of work to straighten out.

Unfortuntely, i am leaving town in a few hours and will be gone for about 4 days.  I don't know if you can wait until I get back or not.  Is this due at some time?
0
 
LVL 22

Expert Comment

by:nietod
ID: 2734124
This is going to be a very bussy morning for me, but if you can get back to me about that stuff at all, I'll try to get back to you at least one mroe time.
0
 

Author Comment

by:anita177
ID: 2734126
I have managed to get the loop going now. What about the adding function? any ideas about how to do this?
0
 

Author Comment

by:anita177
ID: 2734139
I've only got around 10 more days to have this perfect... not long hey!!
Yeah i'm really worried now.. maybe i should just change it to a project in C instead of C++..

Here is what i have of the structure

struct address
{
   char name[20];
   char street[20];
   char city[10];
   char state[10];
   char zip[10];
   struct address *next;
   struct address *prev;
}list_entry;


struct address *start,*last;

main....
0
 
LVL 22

Expert Comment

by:nietod
ID: 2734148
>> What about the adding function? any ideas about how to do this?
store() is the adding function.   I shoed you how to use it in the the read from file function.   Does store() work?
0
 
LVL 22

Expert Comment

by:nietod
ID: 2734170
Stay with C++, it is easier.  

In C++ a struct is a "complete type" so you don't have to use that weird struct/typedef mess that you did in C.  So you have now defined two types  "address" and "list_entry" that are both the same.  (in C "address" would not be a true type.)  Ordinarily you should get rid of the second one, the one that appears after the structure definition and just use the first (calling it whichever you want.)  i.e you should go with

struct address
{
   char name[20];
   char street[20];
   char city[10];
   char state[10];
   char zip[10];
   struct address *next;
   struct address *prev;
};

or the same but calling it list_entry insteadof address

However, due to what I mentioned about not wanting to store the pointers.  Why not split this into two structs.  Like

struct address
{
   char name[20];
   char street[20];
   char city[10];
   char state[10];
   char zip[10];
};

struct list_entry
{
   address Add;;
   struct address *next;
   struct address *prev;
};

now you will allocate and store list_entriy's in the list.  but when you read and write from/to the disk you will use "address"s   (Taht will probably be the only place you use them.
0
 

Author Comment

by:anita177
ID: 2734184
Noooo it doesn't work..
What i want is every time a record is added to thru the store function it should be saved to the txt file (at the end of the for loop)

Every time the user enters the load/read option it should read all data from the file and store it in the linked list....

I hope you can understand what i'm trying to say..

The thing is it dosen't store read the values from the files either..
I know this all sounds a bit complex but i could reallly do with some help
0
 
LVL 22

Expert Comment

by:nietod
ID: 2734638
>> What i want is every time a record is added
>> to thru the store function it should be saved
>> to the txt file (at the
>> end of the for loop)
Are you sure?  Thos woudl usually be seperate operations.  And for good reason.  The reason we use linke dlists is that they are pretty fast and files are pretty slow (about 1000 times slower).  So we usually add all the information to the linked list and do other work with it and then when we are done with the linked list, then we store it to the file.  If you store to the file every time there is change, you can skip th linked list and just use the file, but that is slow

>> Every time the user enters the load/read.
that part I got.  That part has basically been answered.  I wrote the code above to read the info from the file and use the store() function to add the info to the list.

I think you might need to take a step back and start over with a basic linked list design, then start adding the elements that you've written for this case to that desing  (i.e. start with a simple desgine, they copy in the address stuff.)


A typical linked list might be something like
struct Node
{
   int X; // this you would add to.

   Node *Next ;
   Node *Prev;
};

struct List
{
   Node *Head;  
   Node *Tail;
};

// Initialize an emopty linked list.
void InitializeList(List &L)
{
   L.Head = NULL;
   L.Tail = NULL;
};

// Add to linked list.  
// (always adds at the start though.
// takes the int value to be added, yours will data address data.
void Add(List &L,int NewDat)
{
   Noda *NodPtr = new Node;

   NodPtr->X = NewDat; // set address data.
   NodPtr->Next = L.Head.
   NodPtr->Prev = NULL;
   if (L.Head) // If there already were item stored.
     L.Head->Prev = NodPtr; // set old first item's prev pinter
  else // Otherwise if list was empty.
     L.Tail = NodPtr; // Make tail the new item
  L.Head = NodPtr; // Make new item the first item.
}


// Delete speicified item from linked list.  
void Delete(List &L,Noda *ItmPtrt)
{
   if (ItmPtr->Prev) // if this is not the first item
     ItmPtr->Prev->Next = ItmPtr->Next; // Make Previous item skip the one to be deleted.
   else // Otherwise if this was the First item.
       L.Head = ItmPtr->Next; // Make the next item the new First one.

   if (ItmPtr->Next) // if this is not the last item
     ItmPtr->Next->Prev = ItmPtr->Prev; // Make next item skip the one to be deleted.
   else // Otherwise if this was the last item.
       L.Tail = ItmPtr->Prev; // Make the previous item the new last one.

   delete ItmPtr; // Delete the item.
};

Do you see how there is a linked list structure that holds onto the ends of the list and is passed around to any function that uses the list?  You need to start with that basic design.
0
 

Author Comment

by:anita177
ID: 2750827
thanks
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now