From: bmr@reef.cis.ufl.edu (Benedict Rafanello)
Newsgroups: comp.lang.modula2
Subject: Re: Dynamic arrays in Modula-2?
Date: 14 Apr 92 17:08:40 GMT
Reply-To: bmr@reef.cis.ufl.edu (Benedict Rafanello)
Organization: U of Florida. Computer Science Dept.

In article <11353@mindlink.bc.ca>, Changhao_Boh@mindlink.bc.ca (Changhao Boh) writes:
|> DM> How does one express dynamic allocation of single and
|> DM> multi-dimensional arrays in Modula-2?  How does one pass a dynamically
|> DM> allocated multi-dimensional array as an argument to a procedure?
|> DM>
|> DM> For example, if a two or three dimensional array of INTEGERs resides i
|> DM> file on disk, and the dimensions of the data set are specified at the
|> DM> beginning of the file, how can the file be loaded and manipulated
|> DM> using a Modula-2 program?
|> DM>
|> DM> My references on Modula-2 lead me to believe that this elementary
|> DM> operation is difficult or impossible to solve elegantly or portably in
|> DM> Modula-2.
|> 
|> Via user defined datatypes, sir, user defined datatypes, user defined
|> datatypes.
|> 
|> You'll have to write your own opaque data sturctures to accomplish what you
|> want.
|> 
|> To begin,
|> 
|> TYPE
|>   MultiDimArray   = ARRAY [1..100] [1..100] [A..Z] OF CARDINALS;
|> 
|>   aMultiDimArray  = POINTER TO MultiDimArray;
|> 
|> VAR
|>   Array : aMultiDimArray;
|> 
|> BEGIN
|>   ALLOCATE(Array, SIZE(Array^));
|> 
|>   (* Do your stuffs... *)
|> 
|>   DEALLOCATE(Array, SIZE(Array^));
|> 
|> END.
|> 
|> 
|> Good Health.
|> 
|> Changhao.

Another way to dynamically dimension arrays is as follows:

TYPE
  MaxArray = ARRAY[0 .. MAX(CARDINAL)] OF CARDINAL;
  ArrayPointer = POINTER TO MaxArray;

VAR
  Array : ArrayPointer;
  ArraySize : CARDINAL;

     .
     .
     .
  ArraySize := 25;
  ALLOCATE(Array,ArraySize * TSIZE(CARDINAL));
     .
     .
     .
     
You will probably have to adjust the MaxArray declaration for your particular
compiler.  The idea is to declare the largest array that your compiler can 
handle.  Then, you just allocate as much of the array as you actually need 
using the ALLOCATE procedure.  This way, you can create arrays of any size
up to the maximum size declared.  HOWEVER, since you are essentially 
bypassing Modula-2's type checking by doing this, you are responsible for
ensuring that any procedures and functions which manipulate such an object
know the actual size of the object.  This means, essentially, that you can
not use such a type with open array parameters.

PROCEDURE SortArray(VAR Array : ARRAY OF CARDINAL);

With such a declaration, the compiler actually creates a procedure which
looks like the following:

PROCEDURE SortArray(ArraySize : CARDINAL; ArrayAddress : ADDRESS);

Whenever you call SortArray, the compiler translates your call from the first
form into the second so that the SortArray procedure can know how long an array
it is dealing with.  However, when you ALLOCATE the memory for an array and
you do not allocate enough for the full array, the compiler has no way of
knowing this.  It assumes that you allocated enough memory for the full array
and, as a result, does not perform the translation correctly, resulting in the
SortArray procedure thinking your array is larger than it is. 

If you do dynamically dimension arrays like this, it is a VERY GOOD idea to
encapsulate this using an opaque data type, as suggested by Changhao. 

I have used this technique on many occasions and it works quite well, but you
must be very, very careful and pay attention to details.  Errors made here 
can be hard to find and debug, kind of like debugging a 'C' program.

Hope this helps!

Ben