For dynamic arrays, SetLength may take more than one-length
parameter (up to the number of array dimensions). Each parameter
specifies the number of elements along a particular dimension.
Structured types/Data types
To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example:
type TMessageGrid = array of array of string; var Msgs: TMessageGrid;
declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I and J are integer-valued variables:
SetLength(Msgs,I,J);
allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.
You can create multidimensional dynamic arrays that are not rectangular. The first step is to call SetLength, passing it parameters for the first n dimensions of the array. For example:
var Ints: array of array of Integer; SetLength(Ints,10);
allocates ten rows for Ints but no columns. Later, you can allocate the columns one at a time (giving them different lengths); for example:
SetLength(Ints[2], 5);
makes the third column of Ints five integers long. At this point (even if the other columns haven't been allocated) you can assign values to the third column - for example, Ints[2,4] := 6.
The following example uses dynamic arrays (and the IntToStr function declared in the SysUtils unit) to create a triangular matrix of strings.
var A : array of array of string; I, J : Integer; begin SetLength(A, 10); for I := Low(A) to High(A) do begin SetLength(A[I], I); for J := Low(A[I]) to High(A[I]) do A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' '; end; end;
When I first started using FPC, I went through the manuals looking for useful features. I came across both open arrays and dynamic arrays, and thought that they might be valuable. But nowhere could I find any notation for the second, third ... dimension of the array. Without that, open and dynamic arrays were little more than curiosities, possibly useful for 1-dimensional array, but not beyond. Now I see from your email that the notation for the second dimension of an array is Length(xarray[i]) where i is any valid index value (and hence can always be 0). By extension, the third dimension presumably would be Length(xarray[0,0]), and so forth. Never, ever, would I have guessed that would work. It makes sense mathematically, but notationally I would have expected something like Length(xarray,2) for the second dimension. If I had thought of Length(xarray[0]), I would have deemed it so implausible that I never would have tried it. But simply because this is feasible does not mean that one should use it. For one thing, I would like the compiler to generate warning messages if I try to add two matrices of incompatible sizes. I don't want to discover this hours into a computation. That type of checking is one of the main virtues of Pascal. For another, it requires that I code a SetLength statement for every array. That means the array information becomes decentralized. I can't just read down the VAR section of my procedure and learn what I need about the variables, I must consult two sections. Of course I wouldn't have to make every array open, but then I would have a mixture of two kinds of array declarations. This creates an extra maintenance task, making some arrays open, when needed, and restoring them to fixed size when they no longer need to be open. The problem could become fierce when the same declarations are shared by several different procedures. Which one should set the length? How can I be sure the length is set before I reach MyProc? So, once again, I throw my support towards adding vector operations to the compiler. Frank Rubin In a message dated 8/6/2010 12:23:25 P.M. Eastern Daylight Time, harley@umich.edu writes: Dear Frank Rubin, "Except that you have to code every single case separately, 2x6, 3x10, 4x4x4, etc. You need to write a separate routine for every shape of array you want to use." Not so: Use open arrays (always 0-based): type Matrix = array of array of TRing; Youu can write code, roughly: operator * (const A, B: Matrix): Matrix; var RowA, ColA, RowB, ColB, I, J, K: Integer; T: TRing; begin RowA := Length(A); ... ColB := Length(B[0]); if ColA <> RowB then ... SetLength(Result, RowA); for J := 0 to RowA - 1 do SetLength(Result[J], ColB); for I := 0 to RowA - 1 do for K := 0 to ColB - 1 do begin T := Zero; // prefer just 0 for J := 0 to ColA - 1 do T := T + A[I, J]*B[J, K]; Result[I, K] := T; end; end; once and for all, covering all sizes of matrices. The problem I do not yet know how to solve: to do it for all TRing. So I need a type TRing that can include any structure that has + and * operators, and a 0 element: Integers, Floats, Rationals, Gaussian Integers, Polynomials with xxx coefficients,... any possible data type I can define with overloaded +, *, etc. Note that 0 is a problem in itself -- one really needs to overload it too! Frank Heckenbach's first reply to me may contain the answer. I haven't completely digested it yet. Cheers, Harley
-- ============================= Prof. Harley Flanders 3533 Windemere Court Ann Arbor, MI 48105-2867 Home: 734 668 1546 harley@umich.edu =============================