9.9 Records and Arrays--Which, or Both?

Each kind of structured data has its own advantages and disadvantages for specific purposes. Referencing individual items in an array is fairly simple, and a FOR loop is compact, easy to write, and easy to understand. However, the data entered in a single array must all be of the same type, and that makes grouping of different data types into related categories rather difficult.

On the other hand, records can do this kind of grouping of diverse data types, and have great flexibility, but that data cannot be referred to by a numerical position; rather a field name must be employed. Records are (potentially) more elaborate structures than arrays, and the mechanism for using them requires more work to set up, but may be worth it.

In many cases, it is actually possible to use either kind of structure.

Suppose one wanted to design a data structure to hold these class records, say student names, identity numbers, four percentages, and a final letter grade.

One could arrange several arrays in a "side-by-side" fashion as follows:

MODULE Markbook;
FROM STextIO IMPORT
  WriteString, ReadString, SkipLine, WriteLn, WriteChar;
FROM SWholeIO IMPORT
  WriteCard, ReadCard;
  
PROCEDURE GetNum () : REAL;
BEGIN
  (* usual code here *)
  SkipLine;
  RETURN 0.0 (* dummy *)
END GetNum;
TYPE
  Name = ARRAY [0 .. 20] OF CHAR;
  ClassList = ARRAY [1 .. 30] OF Name;
  Idnumber = ARRAY [1 .. 30] OF CARDINAL;
  Marks = ARRAY [1 .. 30], [1 .. 4] OF REAL;
  Grades = ARRAY [1 .. 30] OF CHAR;
VAR
  cmpt141 : ClassList;
  num : Idnumber;
  scores : Marks;
  final : Grades;
  classCount, markCount : CARDINAL;
  
BEGIN
  FOR classCount := 1 TO 30
    DO
      WriteCard (classCount,1);
      WriteChar (")");
      WriteString (" What is the student's name? ");
      ReadString (cmpt141 [classCount]);
      SkipLine;
      WriteLn;
      WriteString ("and the i.d. number? ");
      ReadCard (num [classCount]);
      SkipLine;
      WriteLn;

      FOR markCount := 1 TO 4
        DO
          WriteString ("Give me the mark, with decimal, ");
          WriteString ("for term number ");
          WriteCard (markCount, 10);
          WriteString (" please. ");
          scores [classCount, markCount] := GetNum ();
          (* don't forget to include this procedure *)
          WriteLn;
        END;  (* for markCount *)

    END;  (* for classCount *)

  (* process marks and assign letter grade here *)
END Markbook.

In this approach, the index number classCount within the class effectively groups the data from the different types of arrays. The class is a collection of arrays that are not formally gathered into a single structure, and the data pertinent to a single student must be extracted by knowing the number for that student and using it consistently through all the arrays.

While this approach would work, it hides the real structure of the class, that is, a collection of students, each of whom has various associated data. Consider the following (better) approach:

MODULE Mark2Book;

FROM STextIO IMPORT
  WriteString, ReadString, SkipLine, WriteLn;
FROM SWholeIO IMPORT
  ReadCard;  (* and the other usual imports *)

TYPE
  Name = ARRAY [0 .. 20] OF CHAR;
  Marks = ARRAY [1 .. 4] OF REAL;
  Student =
    RECORD
      moniker : Name;
      idnumber : CARDINAL;
      marks : Marks;
      grade : CHAR;
    END;  (* student *)
  Class = ARRAY [1 .. 30] OF Student;
VAR
  cmpt141 : Class;
  classCount : CARDINAL;

BEGIN
  FOR classCount := 1 TO 30
    DO
      WITH cmpt141 [classCount]
        DO
          WriteString ("What is the student's name? ");
          WriteLn;
          ReadString (moniker);
          SkipLine;
          WriteLn;
          WriteString ("and the i.d. number? ");
          ReadCard (idnumber);
          SkipLine;
          WriteLn;

          (* etc *)
      END; (* With *)

  END;  (* For *)
END Mark2Book.

NOTE: Without the WITH statement, and assuming the declaration of a variable markCount to count through the small array of marks within the record, the correct qualified identifiers would be:

	cmpt141 [classCount].moniker
	cmpt141 [classCount].mark [markCount]
	cmpt141 [classCount].grade
	cmpt141 [classCount].idnumber
	where: 1 <= markCount <= 4.

Arrays of records such as this one are particularly useful for keeping track of individual people and the information about them when those people are also organized into a specific grouping of some kind. Information about students, customers, clients, creditors, employees, and the like can all be arranged in such a fashion.


Contents