Board index » delphi » Strange Behaviour

Strange Behaviour

Hello
Could some one please help me sort this problem out. I am not asking
for my assignment to be done on my behalf. I just need some help to
get this program to read a text file CORRECTLY and store the results
in some variables for manipulation before being placed in a node in a
linked list. The problem is that the variable "TempNum" prints the
first 3 didgets correctly then prints a load of junk. It is supposed
to be a STRING[5]. So I dont know where the other junk is comming
from. The file to be read is"STUDTREC.DAT" which is listed bellow.
The numbers in {} are the collumn widths for the parsing to be
simpler. They are not in the actual file, just HERE for clarity.
The partial program is after the data file. Please reply to
D...@tic.co.za
Thanks
{Data File}
{ 5 }  {     25                   }{    8         }{ 4}{4}{4 }{ 4  }  
346  Pienaar F                COS211-X  15  50  30  10
101  Burger I.J.              COS211-X  20  50   0  35
356  Naude C.W.               COS211-X  10  60  30  20
011  De Wet E.J.              COS211-X  18  40   0  20
201  Smith W.T.               COS211-X  20  50  30  40
340  Dalton J.                COS211-X  20  45  25  35
333  Small J.                 COS211-X  15  35  20   0
401  Stransky J.              COS211-X  10  10   0  35

{Program}
PROGRAM Pointers(Input, Output, InFile);
{
COMPILER      : BORLAND Turbo Pascal 7
AUTHOR        : Dale R. Palmer
DATE          : Saterday 13 April 1996
STUDENT No    : 3009-530-1
COURSE CODE   : COS211-Y
ASSIGNMENT No : 01
QUESTION No   : 01
OBJECTIVE     : Read information from an existing text file and
                store the information in a singly linked list.
                Sort, delete from and print the list as per
                the requirement of the quuestion.
PRE-CONDITION : A text file containing the required data exists.
POST-CONDITION: The list has been sorted, printed and the required
                elements have been deleted and the list has been
                reprinted.
EXTERNAL FILES: "STUDTREC.DAT" This file contains the data for the
                student records that are to be manipulated.

Quote
}

TYPE
PtrType = ^NodeType;
NodeType    = RECORD
  Number : Integer;
  Name   : STRING[25];
  Code   : STRING[8];
  Credits: ARRAY[1..4] OF Integer;
  Total  : Integer;
  Next: PtrType;   {Recursivly points to next node}
END;

VAR
List   : PtrType; {Points to start of list}
InFile : Text;

{===================================================================}
PROCEDURE InsertEntry (VAR List :PtrType);
{Inserts the record into the correct position in the list.}

BEGIN

END; {PROCEDURE InsertEntry}

{===================================================================}
PROCEDURE AddList (VAR List :PtrType;
                   VAR InFile : Text );
{Reads the information for each student, calls a procedure
that inserts the new entry in the correct (sorted) position
in the list, and calculates the total number of credits.}
VAR
  NewNode   : PtrType;
  Ch        : Char;
  Index     : Integer;
  TempNum   : STRING[5];
  TempMk1,
  TempMk2,
  TempMk3,
  TempMk4   : STRING[4];

BEGIN
      New(NewNode);
      IF (List = NIL) THEN List := NewNode;
      FOR Index := 1 TO 5 DO {Read in student no.}
      BEGIN                  {Size = 5}
        Read(InFile,Ch);
        IF (Ord(Ch) >= 48) AND (Ord(Ch) <= 57) THEN
          TempNum[Index] := Ch;
      END;
      WriteLn(TempNum:5);
      WriteLn('TempNum');
      ReadLn;
      FOR Index := 6 TO 30 DO {Read in student name.}
      BEGIN                   {Size = 25}
        Read(InFile,Ch);
        {NewNode^.Name:=}
      END;
      FOR Index := 31 TO 38 DO {Read in course code.}
      BEGIN                    {Size = 8}
        Read(InFile,Ch);
      END;
      FOR Index := 39 TO 42 DO {Read in 1st mark.}
      BEGIN                    {Size = 4}
        Read(InFile,Ch);
      END;
      FOR Index := 43 TO 46 DO {Read in 2nd mark.}
      BEGIN                    {Size = 4}
        Read(InFile,Ch);
      END;
      FOR Index := 47 TO 50 DO {Read in 3rd mark.}
      BEGIN                    {Size = 4}
        Read(InFile,Ch);
      END;
      FOR Index := 51 TO 54 DO {Read in 4th mark.}
      BEGIN                    {Size = 3}
        Read(InFile,Ch);
      END;

  {InsertEntry(List);}

END; {PROCEDURE AddList}
{===================================================================}
PROCEDURE Delete (VAR List : PtrType);
{Deletes all the entries of students who failed to obtain
admission to the examination.}

BEGIN

END; {PROCEDURE Delete}
{====================================================================}
PROCEDURE PrintList (List : PtrType);
{Prints the contents of the list.}

BEGIN

END; {PROCEDURE PrintList}
{====================================================================}
BEGIN {MAIN}
  List := NIL;

  Assign(InFile,'C:\TP\PROGRAMS\STUDTREC.DAT');
  Reset(InFile);
  WHILE (NOT Eof(InFile)) DO
    BEGIN
    WHILE (NOT EoLn(InFile)) DO
      BEGIN
      AddList(List, InFile);
      END; {EoLn}
      ReadLn(InFile);
      WriteLn;
    END; {Eof}
  Close(InFile);

  WriteLn('THE END');
  ReadLn;
END.  {MAIN}
{===================================================================}

 

Re:Strange Behaviour


Quote
In article <4kqutm$...@cpt.pix.za> Dale Palmer wrote:

[snip]

Quote
>The problem is that the variable "TempNum" prints the
>first 3 didgets correctly then prints a load of junk.

snip]

PROCEDURE AddList (VAR List :PtrType;

Quote
>                   VAR InFile : Text );
>{Reads the information for each student, calls a procedure
>that inserts the new entry in the correct (sorted) position
>in the list, and calculates the total number of credits.}
>VAR
>  NewNode   : PtrType;
>  Ch        : Char;
>  Index     : Integer;
>  TempNum   : STRING[5];
>  TempMk1,
>  TempMk2,
>  TempMk3,
>  TempMk4   : STRING[4];

>BEGIN
>      New(NewNode);
>      IF (List = NIL) THEN List := NewNode;
>      FOR Index := 1 TO 5 DO {Read in student no.}
>      BEGIN                  {Size = 5}
>        Read(InFile,Ch);
>        IF (Ord(Ch) >= 48) AND (Ord(Ch) <= 57) THEN
>          TempNum[Index] := Ch;
>      END;
>      WriteLn(TempNum:5);
>      WriteLn('TempNum');
>      ReadLn;

Hi Dale.  The problem is that the length of TempNum was never
established.  Yes, it is defined as string[5], but that means it is
a string that can contain a maximum of 5-Characters.  In your read
you stuff the characters but never do anything to set the string's
length.  Hence, it could "look" like anything from a 0 to a 255
character string!  The strings actual length in this case (byte at
TempNum[0]) contains whatever was on the stack were TempNum was
placed by the compiler. The following is one solution to your
problem:

    TempNum := '';
    FOR Index := 1 TO 5 DO {Read in student no.}
    BEGIN                  {Size = 5}
       Read(InFile,Ch);
       IF (Ord(Ch) >= 48) AND (Ord(Ch) <= 57) THEN Begin
          Inc(TempNum[0]);
          TempNum[ Ord(TempNum[0]) ] := Ch;
       End;
    END;

Now that you have an answer to what happened to TempNum, I'd like
to show you a different way of reading columnar text data.  TP/BP
will allow us to access a 1-Based array of character, whose size is
not greater than 255 Chars, as if it were a string.  So, we define
a string to make it easy to read lines from the file and define
fields on top of it as array[1..n] of Char to make it easy to
access the data.  To define a data overlay of this type we simply
use a variant record.

TYPE
   tTextRecord = RECORD
   Case Integer of
      1: (Line: String;                  { Could be String[55]   }
      2: (Len   : Byte;                  { String length         }
          Number: Array[1.. 5] of Char;  { First five characters }
          Name  : Array[1..25] of Char;  { Next 25 characters    }
          Code  : Array[1.. 8] of Char;
          Credit: Array[1.. 4] of Array[1..4] of Char;
      );
   END;

Remember that the string must be long enough to contain all the
fields.  If it is longer it simply wastes data space, but that
is usually no big thing, especially if it is a local variable.

The following fragment shows how it all fits together.

VAR NewNode: PtrType;
    Rec: tTextRecord;
    err: Integer;

BEGIN
    New(NewNode);
    Readln(InFile, Rec.Line);
    Val(Rec.Number, NewNode^.Number, err);
    If Err <> 0 Then
       {-- what do you want to do if it's not a number? --};

    NewNode^.Name := Rec.Name;

    ... etc.

END;

If you are afraid of reading a "short" line, you might fill Rec
with zeros or spaces before reading the line.  That way fields
beyond the actual length of the line that was read will be nul or
space filled.  (example:  FillChar(Rec, Sizeof(Rec), 0); )

I notice that your AddList procedure automatically inserts the
first node into the list (e,g If List = NIL Then List := NewNode).  
I know of two ways to "ground" a linked list.  One is to use a NIL
pointer (e.g if Next = NIL Then {node is last node}), the other is
to have the node point back to the first node (e.g. if Next = List
Then {node is last node}).  Just thought I'd mention it so you
don't create yourself more heartache.

                      ...red

Knowledge is one of the few things that you
can give away and still keep for yourself.

Other Threads