From: mgmam@uxa.ecn.bgu.edu (Mark A. Morrell)
Newsgroups: comp.programming
Subject: Re: saving pointers to a file
Keywords: pointers pascal file saving anything else everyone :)
Date: 1 Oct 92 04:03:45 GMT
Organization: Educational Computing Network

In article <BuuDpw.J9u@acsu.buffalo.edu> 
	masdough@ubvmsb.cc.buffalo.edu (Dough the Demented) writes:

>Hello,
>  I want to be able to save a "structure" containing multiple pointers to a
>file.. I need some ideas on how to do it.. (I have a few.. but i want the best)
>
>sample structure
>
>aaa record
>  1 stat field of type bbb
>  9 pointers to type aaa
>end aaa
>bbb record
>  a bunch of fields
>  1 pointer to type ccc
>end bbb
>ccc record
>  a few data fields
>  1 pointer to type ccc
>end ccc
>
>I need to save all of the fields in all of the structures (so i can rebuild
>everything later..)  I could go through and save everything in one file..
>going through each structure, field-by-field.. Or I could put aaa in one file
>and ccc in another..
>Either way, I need to keep references of what points to what... What is the
>best way to do this.. Assign a number to each "object" and save the number..?
>
>Any help would be greatly appreciated :)
>Thanks!
>Dough

This is really easier than it looks (aren't the best solutions always
the easiest?)

You just traverse your tree structure, writing the data out as you go,
including the pointer fields.  There are two reason for keeping the
pointer fields, the first of which is that it is just easier to keep
them than it is to try to either zero them out or remove them entirely.
The second reason follows later...

Please forgive the coding examples, they would not compile in any
language, but are something similar to Modula-2.

Assuming a data structure like this:

pA = POINTER TO A;
A = RECORD
   Data :  Some static data structure;
   pB   :  POINTER TO B;
   Next :  pA;
END;

Write the data like this:

WHILE pA # NIL DO
   WriteA( pA );
   IF pA^.pB # NIL THEN
      WriteB( pA^.pB );
      Deallocate( pA^.pB );
   END;
   p := pA;
   pA := pA^.Next;
   Deallocate( p );
END;

You read the data in a similar manner like this:

ReadA( pA );
WHILE NOT EOF DO
     IF pA^.pB # NIL THEN
         Allocate( pA^.pB );
         ReadB( pA^.pB );
     END;
     IF pA^.Next # NIL THEN
	Allocate( pA^.Next );
        ReadA( pA^.Next );
        pA := pA^.Next;
     END;
END;

You may have to tweak this a little bit, but let me see if I can
summarize why this works:  

1) You know the size and structure of the first element of the 
   list when you write it out.  
2) You traverse your tree following a predetermined algorithm.
3) When you read the data back in, it will follow the same pattern
   it did when you wrote it out, beginning with the known first element.
4) You always know what the next structure is, and where it belongs,
   because you are following the same algorithm when you read back in.
5) You determine whether a pointer actually points to something by
   comparing it with NIL when you read it in.  (Of the values a 
   pointer may assume, this is the only one while will retain a
   valid value when you read it back in.)
6) If the next pointer in your algorithm is not NIL, then the next
   chunk of data in your file is meant to be the data it points to.

So in this manner, you can simply write out all your data sequentially,
and then read it back in again.

I hope I have made this matter sufficiently obscure for everyone who
tries to implement it.  If there are any questions, just holler.
However, I know this method works, because I use it.  If you don't
understand it's because I write code better than I explain it.

If anyone wants, just send me a piece of e-mail, and I'll give you a
chunk of real live working code which actually does what I am trying to
explain to you.

Happy Computing...                              Mark A. Morrell
Newsgroups: comp.programming