[comp.lang.pascal] Pointers..

dragon@westfort.UUCP (The Mystic) (05/16/89)

        I managed to get pointers working w/ files, yet for some reason when I 
come back to the file, it's all garbage.. I realize that the pointers were for 
memory vars only, but this program created a disk file as I specified in my 
assign command.. Perhaps an example..

Program testheap;
 
uses dos,crt;
 
Type
   boardtype=^boardrec;
   boardrec=record
name:string[20];
age:integer;
end;
Var
  msgbase:boardtype;
  messagebase:file of boardtype;
 
procedure getest;
begin
 clrscr;
  write('Enter Your Name: '); readln(msgbase^.name);
  write('Enter Your Age.: '); readln(msgbase^.age);
  assign(messagebase,'c:\pascal\testfile.dat');
  {$I-} reset(messagebase); {$I+}
     if ioresult<>0 then rewrite(messagebase);
  write(messagebase,msgbase);
  close(messagebase);
end;
 
procedure readtest;
begin
  assign(messagebase,'c:\pascal\testfile.dat');
  writeln;
  {$I-} reset(messagebase); {$I+}
     if ioresult<>0 then rewrite(messagebase);
  read(messagebase,msgbase);
  with msgbase^ do begin
     writeln('Your name is: ',name);
     writeln('Your Age is.: ',age);
     delay(5000);
   close(messagebase);
  end;
end;
 
begin getest; readtest; end.

If I take out the getest from the routine, after I've run other programs, it 
brings up garbage... Why?

R_Tim_Coslet@cup.portal.com (05/30/89)

In article: <3398@westfort.UUCP>
	dragon@westfort.UUCP (The Mystic) Writes...
>
>Program testheap;
> 
>uses dos,crt;
> 
>Type
>   boardtype=^boardrec;		<-- a POINTER type
>   boardrec=record
>name:string[20];
>age:integer;
>end;
>Var
>  msgbase:boardtype;
>  messagebase:file of boardtype;	<-- this is a file of POINTERS !?!?!
> 
>procedure getest;
>begin
	[deleted]
>  write(messagebase,msgbase);		<-- notice he ONLY wrote the POINTER!
>  close(messagebase);
>end;
> 
>procedure readtest;
>begin
	[deleted]
>end;
> 
>begin getest; readtest; end.
>
>If I take out the getest from the routine, after I've run other programs, it 
>brings up garbage... Why?

Very simple... the records were not saved, only the pointers.
You will notice that the "messagebase" file is ONLY a file of pointers.

These pointers are pointers to memory locations, which when the program
is run as originally written were created by the call to "getest" and
happen to still exist when "readtest" is called. However if "getest" is
taken out the records do not exist when "readtest" is called.

In my opinion you should NEVER write a file containing pointer variables
(or pointer fields of records): pointers are addresses in memory... and 
those memory locations may (probably will) contain other data when the file
finally gets read again (even if the data was also saved in a file).

                                        R. Tim Coslet

Usenet: R_Tim_Coslet@cup.portal.com
BIX:    r.tim_coslet 

pgcomp@pbinfo.UUCP (Projektgr. Uebersetzerbau) (05/30/89)

In article <3398@westfort.UUCP>, dragon@westfort.UUCP (The Mystic) writes:
] 
]         I managed to get pointers working w/ files, yet for some reason when I 
] come back to the file, it's all garbage.. I realize that the pointers were for 
] memory vars only, but this program created a disk file as I specified in my 
] assign command.. Perhaps an example..
] 
] Program testheap;
]  
] uses dos,crt;
]  
] Type
]    boardtype=^boardrec;
]    boardrec=record
] name:string[20];
] age:integer;
] end;
] Var
]   msgbase:boardtype;
]   messagebase:file of boardtype;
]  
] procedure getest;
] begin
]  clrscr;
]   write('Enter Your Name: '); readln(msgbase^.name);
]   write('Enter Your Age.: '); readln(msgbase^.age);
]   assign(messagebase,'c:\pascal\testfile.dat');
]   {$I-} reset(messagebase); {$I+}
]      if ioresult<>0 then rewrite(messagebase);
]   write(messagebase,msgbase);
]   close(messagebase);
] end;
]  
] procedure readtest;
] begin
]   assign(messagebase,'c:\pascal\testfile.dat');
]   writeln;
]   {$I-} reset(messagebase); {$I+}
]      if ioresult<>0 then rewrite(messagebase);
]   read(messagebase,msgbase);
]   with msgbase^ do begin
]      writeln('Your name is: ',name);
]      writeln('Your Age is.: ',age);
]      delay(5000);
]    close(messagebase);
]   end;
] end;
]  
] begin getest; readtest; end.
] 
] If I take out the getest from the routine, after I've run other programs, it 
] brings up garbage... Why?


Didn't you remember the difference between pointers and variables ?
You declared msgbase as a pointer to boardrec, but you didn't allocate 
(* new(msgbase) *) any memory space for holding an element of type boardrec. 
Thus any operation with msgbase must fail due to writing in nonallocated 
memory space.

			   thomas roemke
			   (tt)

mitch@arcturus.UUCP (Mitchell S. Gorman) (05/31/89)

What you  should be doing is manipulating a file of boardREC, not
boardTYPE.  Saving pointers into memory locations in a file is not a good
way to do things... there's absolutely NO guarantee that the next time you
run the program, memory will look exactly the way it did the first time!

	Mitch @ Rockwell, Anaheim

Disclaimer:	I KNOW!! I've TRIED!!

diamond@diamond.csl.sony.junet (Norman Diamond) (05/31/89)

In article <3398@westfort.UUCP> westfort!dragon@tut.cis.ohio-state.edu writes:

>        I managed to get pointers working w/ files, yet for some reason when I 
>come back to the file, it's all garbage.. I realize that the pointers were for 
>memory vars only, but this program created a disk file as I specified in my 
>assign command.. Perhaps an example..

When a program terminates, its variables lose their values.  This
includes variables named in the programs, and variables created by
"new".  When you write a variable to a file, its value stays there
and the value can be read back later.  You did not write any variables
of type "boardtype", so there were no names or ages in the file.  You
only wrote pointer variables, so there were only addresses.  Your
second execution of the program did not create the same exact
boardtype variables with "new".

Your first execution must write variables of type "boardtype", and
your second execution must create the variables again (calling "new")
and read in the "boardtype" variables, in order to remember names and
ages.

--
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.co.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-implementing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

kpfleger@phoenix.Princeton.EDU (Karl Robert Pfleger) (06/01/89)

Don't rag on the idea of storing linked lists in disk files. It is a
completely natural thing to do. After all, what is a linked list? A
sequencial list of records. This is exactly what a disk file contains.
Saving and loading linked lists is easy.

First of all, you have to get the linked list data structure right. I
don't remember any follow up articles so far point out that the
following is incomplete.

In article <3398@westfort.UUCP> westfort!dragon@tut.cis.ohio-state.edu writes:
>Type
>   boardtype=^boardrec;
>   boardrec=record
>name:string[20];
>age:integer;
>end;

This just defines a record with a pointer to it. A field of type
boardtype must be added to the record boardrec to make this a potential
linked list structure. But since we don't need to save the pointers in
the file, it would be best to define the structure as follows:

type
  boardtype=^boardrec;
  rectype=record
            name: string[20];       > or
            age: integer;           > whatever
           end;
  boardrec=record
             info: rectype;
             next: boardtype;
            end;

Now we can define a file to be a file of info. To save the linked list,
we just trace through the list saving info records. If t is a pointer and
f a file we do:

repeat
  write (f,t^.info);
  t:=t^.next;
 until t=nil; (or whatever tail node you use)

Reading in a disk file to a linked list is just as simple. The only
added complication is that we have to do a new(t^.next) call to allocate
memory for the next node in the list to be created each time.

I realize that most of you probably know this, but someone obviously
didn't and none of the follow up articles were very instructive about
what to do.  

You can also store slightly more interesting
structures (if you ever have a need to) like binary trees as long as the
structure has a specific form. As long as you know which order the data
was saved in, you can load it back. A couple possibilities for binary
trees exist.

A level order traversal:             1
                                 2       3
                               4   5   6   7
                              8 9 etc.

An inorder traversal:                8
                                 4       12
                               2   6  10    14
                              1 3 5 7 9 11 13 15

The routines for saving these work the same as the linked list, only you
use a tree traversal (whichever) to visit the nodes. The routines for
loading these things will, of course, be more complicated. The easiest
approach would be to load the file into an array an index into it
judiciously, but this could mean lots of extra memory.

     - KPfleg 
                  kpfleger@phoenix.princeton.edu
                  kpfleger@pucc.princeton.edu
                  or just kpfleger@pucc for BITNET sites

Hope someone found it interesting or helpful. I wouldn't want to cost
the net 'hundreds if not thousands of dollars' for nothing.

kent@swrinde.nde.swri.edu (Kent D. Polk) (06/02/89)

In article <8835@phoenix.Princeton.EDU> kpfleger@phoenix.Princeton.EDU (Karl Robert Pfleger) writes:
[...]
>repeat
>  write (f,t^.info);
   s:= t;           <---------
>  t:=t^.next;
   dispose (s);     <---------
> until t=nil; (or whatever tail node you use)

Unless you are exiting & expect Pascal to release your dynamically
allocated memory, you might want to dispose of it explicitly. 
Otherwise ...  :^)
Also, don't forget your header (and maybe trailer) nodes.

>Reading in a disk file to a linked list is just as simple.
[...]
>                               As long as you know which order the data
>was saved in, you can load it back. A couple possibilities for binary
>trees exist.
[...]
>                                                     The routines for
>loading these things will, of course, be more complicated. The easiest

Why not use the Insert routines which created the list in the first
place? That's the easiest, especially when you have multiple indexed
links to the data or a tree which can be created differently based on
what you want to do with it.

>     - KPfleg 

Kent Polk

d87-jse@nada.kth.se (Joakim Sernbrant) (06/02/89)

Talking about pointers, is there any reason why I shouldn't do this on
a PC running DOS without multitasking:

while p <> nil do begin
  dispose(p);
  p := p^.next;
end;

???

I understand that with multitasking (OS/2 ?), an other process might
get the released memory before I get to assign p, but what about DOS ?

-- 
--  Joakim Sernbrant, Royal Institute of Technology, Stockholm, Sweden
--  Internet:  d87-jse@nada.kth.se
--

milne@ics.uci.edu (Alastair Milne) (06/02/89)

d87-jse@nada.kth.se (Joakim Sernbrant) writes
>Talking about pointers, is there any reason why I shouldn't do this on
>a PC running DOS without multitasking:
>
>while p <> nil do begin
>  dispose(p);
>  p := p^.next;
>end;

    Problems here start well before multitasking: you are accessing part of a
    variable (p^.next) after having destroyed it (dispose(p);).  Now it may be
    that your implementation of dispose doesn't actually impede your doing
    this (some Pascal's, for instance, have dispose return the pointer passed
    to them set to NIL), but I certainly wouldn't rely on it -- at best, it
    would be very untransportable.

    What I think you actually want is:

       while p <> nil do begin
	  holder := p;
	  p := p^.next;
	  Dispose( holder);
	  end;

     I don't know nearly enough of how OS/2 handles task-switching
     (time-slicing? priority queues?) to know what operations are guarded and
     what aren't; but I think this algorithm should dispose of a list with no
     incoherence problems.  At most, some concurrent application might be
     grabbing the memory this one releases as it is released -- but that
     should cause no problems.


     Alastair Milne

soper@xenna.UUCP (Pete Soper,,,) (06/02/89)

From article <1150@draken.nada.kth.se>, 
  by d87-jse@nada.kth.se (Joakim Sernbrant):
> Talking about pointers, is there any reason why I shouldn't do this on
> a PC running DOS without multitasking:
> 
> while p <> nil do begin
>   dispose(p);
>   p := p^.next;
> end;
 
  Yes. You might want your program to have a chance to make you rich and
famous by being portable.
  A great many heap managers (like ours) would invalidate p after the dispose
so the link assignment would blow up. Why can't you put up with an extra
assignment to avoid this? Whether it is your unspecified DOS Pascal compiler or
whatever, the overhead of a dispose would likely overwhelm the cost of an 
extra assignment that avoided dereferencing p after it had been disposed.
----------------------------------------------------------------------
Pete Soper                                             +1 919 481 3730
arpa: soper@encore.com        uucp: {bu-cs,decvax,necntc}!encore!soper 
Encore Computer Corp, 901 Kildaire Farm Rd, bldg D, Cary, NC 27511 USA

diamond@diamond.csl.sony.junet (Norman Diamond) (06/05/89)

In article <1150@draken.nada.kth.se> d87-jse@nada.kth.se (Joakim Sernbrant) writes:

>Talking about pointers, is there any reason why I shouldn't do this on
>a PC running DOS without multitasking:
>
>while p <> nil do begin
>  dispose(p);
>  p := p^.next;
>end;
>
>???

If you don't care what bugs you incorporate into your programs, for
which you might spend days later debugging (e.g. when you get the next
release of a compiler, or that multitasking OS, etc.), then of course
you can play however you like.  If you're working for someone like me
then you don't want to do it, at least not deliberately, because you'd
get fired.

Also there is a chance that some kindly compiler might help you find
your bugs, perhaps by setting p to NIL when the dispose is done.  And
some other kindly compiler might do garbage collection for you, which
renders ordinary pointers a little bit more expensive to use but which
does have some demand in quite a lot of languages now.

--
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.co.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-implementing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?