[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]

{
witold@aed.dsto.gov.au

{--------------------------------------------------------------------------}

Program TestMat(Input,Output);

{ Description: Allocating/deallocating 2D arrays larger than 64kB in size  }
{ Date       : 12 December 1994                                            }
{ Author     : Witold Waldman                                              }
{                                                                          }
{ This is a sample program showing how to go about using the matrix memory }
{ allocation/deallocation functions contained in the unit MATMEM.          }
{                                                                          }
{ In this example, a two-dimensional array of double precision numbers is  }
{ allocated. The total size of the array is chosen to be greater than the  }
{ maximum size of a 64kB data segment to illustrate how the techniques     }
{ that are implemented here can be used to work with large matrices.       }
{                                                                          }
{ After the array storage has been created, each element of the array is   }
{ filled with a unique number, and the last element in each row is then    }
{ displayed on the screen.                                                 }
{                                                                          }
{ Finally, the array is deallocated and the heap is checked to see if any  }
{ memory leaks have occurred.                                              }
{                                                                          }
{ Because all memory allocation occurs on the heap at run-time, the use    }
{ of extended memory is automatic if the Borland Pascal program is         }
{ compiled as a protected mode application.                                }
{                                                                          }
{ The basic idea for the approach used here was taken from a short article }
{ by William F. Polik (PC Tech Journal, December 1986, p. 49).             }
{                                                                          }
{ Feel free to use this code as you see fit, and I hope that it provides   }
{ a useful example of how large arrays can be allocated and accessed from  }
{ Turbo Pascal without suffering too greatly from the 64kB segment limit   }
{ imposed by the medium memory model used by the compiler.                 }
{                                                                          }
{ NOTE: The source code to the MATMEM unit is located at the bottom of     }
{       this program. Just cut and paste it into a separate file.          }

{$N+}
{$E+}

{$M 65520,250000,655360 }

Uses CRT,MATMEM;

var
  AD        : pArrayDD;    { Pointer to a two-dimensional array of doubles }
  NR        : word;        { Maximum row dimension of array                }
  NC        : word;        { Maximum column dimension of array             }
  i         : word;        { Index variable used for traversing rows       }
  j         : word;        { Index variable used for traversing columns    }
  MemBefore : longint;     { Memory available before array allocation      }
  MemAlloc  : longint;     { Memory available after array allocation       }

begin

  ClrScr;

  { Configure the size of the 2D matrix we wish to allocate }

  NR := 2;
  NC := MaxSizeArrayD;

  { Allocate dynamic memory for the 2D array }

  MemBefore := MaxAvail;

  AD := NewArrayDD(NR,NC);

  MemAlloc := MaxAvail;

  { Check to see whether the pointer is nil. If it is, then }
  { the allocation of the array failed.                     }

  If AD = nil then
    begin
    Writeln('Not enough dynamic memory available for array.');
    Halt;
    end;

  { Write some info about what was just allocated on the heap }

  Writeln('Dynamic memory allocated for array = ',MemBefore-MaxAvail,' bytes');
  Writeln;
  Writeln('Number of array elements = ',(NR+1)*(NC+1));
  Writeln;

  { Proceed to access each element in the array and store a unique number   }
  { in each and every array location. Display the value of the last element }
  { in each row of the array for checking purposes.                         }

  For i := 0 to NR do
    begin
    For j := 0 to NC do
      begin
      AD^[i]^[j] := j*1.0E0 + i*100000.0E0;
      end;
    Writeln('Selected array contents: AD^[',i,']^[',NC,'] = ',
            AD^[i]^[NC]:10:1);
    end;

  { Deallocate dynamic memory for the 2D array }

  AD := DisposeArrayDD(AD,NR,NC);

  Writeln;
  Writeln('Dynamic memory deallocated = ',MaxAvail-MemAlloc,' bytes');

  If MaxAvail = MemBefore then
    begin
    Writeln;
    Writeln('No memory leaks detected.');
    end
  else
    begin
    Writeln;
    Writeln('A memory leak has been detected.');
    end;

end.

{---------------------------------------------------------------------------}

{$N+}
{$E+}

UNIT MATMEM;

INTERFACE

const
  PtrSize         = SizeOf(Pointer);
  MaxSegmentSize  = 65535;
  MaxSizeArrayP   = MaxSegmentSize div PtrSize         - 1;
  MaxSizeArrayR   = MaxSegmentSize div SizeOf(Real)    - 1;
  MaxSizeArrayS   = MaxSegmentSize div SizeOf(Single)  - 1;
  MaxSizeArrayD   = MaxSegmentSize div SizeOf(Double)  - 1;
  MaxSizeArrayI   = MaxSegmentSize div SizeOf(Integer) - 1;

type
  ArrayPtr = array [0..MaxSizeArrayP] of Pointer;
  ArrayR   = array [0..MaxSizeArrayR] of Real;
  ArrayS   = array [0..MaxSizeArrayS] of Single;
  ArrayD   = array [0..MaxSizeArrayD] of Double;
  ArrayI   = array [0..MaxSizeArrayI] of Integer;

  ArrayRR  = array [0..MaxSizeArrayP-1] of ^ArrayR;
  ArraySS  = array [0..MaxSizeArrayP-1] of ^ArrayS;
  ArrayDD  = array [0..MaxSizeArrayP-1] of ^ArrayD;
  ArrayII  = array [0..MaxSizeArrayP-1] of ^ArrayI;

  pArrayR  = ^ArrayR;
  pArrayS  = ^ArrayS;
  pArrayD  = ^ArrayD;
  pArrayI  = ^ArrayI;

  pArrayRR = ^ArrayRR;
  pArraySS = ^ArraySS;
  pArrayDD = ^ArrayDD;
  pArrayII = ^ArrayII;

{ Functions for allocating/deallocating single dimensional arrays. }
{                                                               }
{ NRmax = maximum number of rows allocated/deallocated.         }
{ NCmax = maximum number of columns allocated/deallocated.      }

function NewArrayS(Nmax:Word):Pointer;

function DisposeArrayS(A:Pointer; Nmax:Word):Pointer;

function NewArrayD(Nmax:Word):Pointer;

function DisposeArrayD(A:Pointer; Nmax:Word):Pointer;

function NewArrayI(Nmax:Word):Pointer;

function DisposeArrayI(A:Pointer; Nmax:Word):Pointer;

function NewArrayR(Nmax:Word):Pointer;

function DisposeArrayR(A:Pointer; Nmax:Word):Pointer;

{ Functions for allocating/deallocating two dimensional arrays. }
{                                                               }
{ NRmax = maximum number of rows allocated/deallocated.         }
{ NCmax = maximum number of columns allocated/deallocated.      }

function NewArraySS(NRmax,NCmax:Word):Pointer;

function DisposeArraySS(A:Pointer; NRmax,NCmax:Word):Pointer;

function NewArrayDD(NRmax,NCmax:Word):Pointer;

function DisposeArrayDD(A:Pointer; NRmax,NCmax:Word):Pointer;

function NewArrayII(NRmax,NCmax:Word):Pointer;

function DisposeArrayII(A:Pointer; NRmax,NCmax:Word):Pointer;

function NewArrayRR(NRmax,NCmax:Word):Pointer;

function DisposeArrayRR(A:Pointer; NRmax,NCmax:Word):Pointer;

IMPLEMENTATION

{==========================================================================}


function NewArray1D(Nmax:Word; DataSize:Integer):Pointer;

var
  MemP : Word;
  P    : Pointer;

begin
  MemP := (Nmax+1)*DataSize;
  If MaxAvail >= MemP then
    GetMem(P,MemP)
  else
    P := nil;
  NewArray1D := P;
end;

{==========================================================================}


function DisposeArray1D(A:Pointer; Nmax:Word; DataSize:Integer):Pointer;

begin
  If A <> nil then
    begin
    FreeMem(A,(Nmax+1)*DataSize);
    DisposeArray1D := nil;
    end;
end;

{==========================================================================}


function DisposeArray2D(A:Pointer; NRmax,NCmax:Word; DataSize:Integer):Pointer;

var
  I : Word;
  Q : ^ArrayPtr;

begin
  If A <> nil then
    begin
    Q := A;
    For I := 0 to NRmax do
      begin
      If Q^[I] <> nil then
        FreeMem(Q^[I],(NCmax+1)*DataSize);
      end;
    FreeMem(A,(NRmax+1)*PtrSize);
    DisposeArray2D := nil;
    end;
end;

{==========================================================================}


function NewArray2D(NRmax,NCmax:Word; DataSize:Integer):Pointer;

var
  Error : Boolean;
  I     : Word;
  MemP  : Word;        { Memory for pointers to each row of data }
  MemR  : Word;        { Memory for row of data                  }
  P     : ^ArrayPtr;

begin
  MemP := (NRmax+1)*PtrSize;
  If MaxAvail >= MemP then
    GetMem(P,MemP)
  else
    P := nil;
  If P <> nil then
    begin
    Error := false;
    MemR  := (NCmax+1)*DataSize;
    For I := 0 to NRmax do
      begin
      If MaxAvail >= MemR then
        GetMem(P^[I],MemR)
      else
        begin
        Error := true;
        P^[I] := nil;
        end;
      end;
    If Error then
      begin
      P := DisposeArray2D(P,NRmax,NCmax,DataSize);
      end;
    end;
  NewArray2D := P;
end;

{==========================================================================}


function NewArrayS(Nmax:Word):Pointer;

begin
  NewArrayS := NewArray1D(Nmax,SizeOf(Single));
end;

{==========================================================================}


function DisposeArrayS(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayS := DisposeArray1D(A,Nmax,SizeOf(Single));
end;

{==========================================================================}


function NewArrayD(Nmax:Word):Pointer;

begin
  NewArrayD := NewArray1D(Nmax,SizeOf(Double));
end;

{==========================================================================}


function DisposeArrayD(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayD := DisposeArray1D(A,Nmax,SizeOf(Double));
end;

{==========================================================================}


function NewArrayI(Nmax:Word):Pointer;

begin
  NewArrayI := NewArray1D(Nmax,SizeOf(Integer));
end;

{==========================================================================}


function DisposeArrayI(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayI := DisposeArray1D(A,Nmax,SizeOf(Integer));
end;

{==========================================================================}


function NewArrayR(Nmax:Word):Pointer;

begin
  NewArrayR := NewArray1D(Nmax,SizeOf(Real));
end;

{==========================================================================}


function DisposeArrayR(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayR := DisposeArray1D(A,Nmax,SizeOf(Real));
end;

{==========================================================================}


function NewArraySS(NRmax,NCmax:Word):Pointer;

begin
  NewArraySS := NewArray2D(NRmax,NCmax,SizeOf(Single));
end;

{==========================================================================}


function DisposeArraySS(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArraySS := DisposeArray2D(A,NRmax,NCmax,SizeOf(Single));
end;

{==========================================================================}


function NewArrayDD(NRmax,NCmax:Word):Pointer;

begin
  NewArrayDD := NewArray2D(NRmax,NCmax,SizeOf(Double));
end;

{==========================================================================}


function DisposeArrayDD(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArrayDD := DisposeArray2D(A,NRmax,NCmax,SizeOf(Double));
end;

{==========================================================================}


function NewArrayII(NRmax,NCmax:Word):Pointer;

begin
  NewArrayII := NewArray2D(NRmax,NCmax,SizeOf(Integer));
end;

{==========================================================================}


function DisposeArrayII(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArrayII := DisposeArray2D(A,NRmax,NCmax,SizeOf(Integer));
end;

{==========================================================================}


function NewArrayRR(NRmax,NCmax:Word):Pointer;

begin
  NewArrayRR := NewArray2D(NRmax,NCmax,SizeOf(Real));
end;

{==========================================================================}


function DisposeArrayRR(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArrayRR := DisposeArray2D(A,NRmax,NCmax,SizeOf(Real));
end;

END.

{$N+}
{$E+}

UNIT MATMEM;

INTERFACE

const
  PtrSize         = SizeOf(Pointer);
  MaxSegmentSize  = 65535;
  MaxSizeArrayP   = MaxSegmentSize div PtrSize         - 1;
  MaxSizeArrayR   = MaxSegmentSize div SizeOf(Real)    - 1;
  MaxSizeArrayS   = MaxSegmentSize div SizeOf(Single)  - 1;
  MaxSizeArrayD   = MaxSegmentSize div SizeOf(Double)  - 1;
  MaxSizeArrayI   = MaxSegmentSize div SizeOf(Integer) - 1;

type
  ArrayPtr = array [0..MaxSizeArrayP] of Pointer;
  ArrayR   = array [0..MaxSizeArrayR] of Real;
  ArrayS   = array [0..MaxSizeArrayS] of Single;
  ArrayD   = array [0..MaxSizeArrayD] of Double;
  ArrayI   = array [0..MaxSizeArrayI] of Integer;

  ArrayRR  = array [0..MaxSizeArrayP] of ^ArrayR;
  ArraySS  = array [0..MaxSizeArrayP] of ^ArrayS;
  ArrayDD  = array [0..MaxSizeArrayP] of ^ArrayD;
  ArrayII  = array [0..MaxSizeArrayP] of ^ArrayI;

  pArrayR  = ^ArrayR;
  pArrayS  = ^ArrayS;
  pArrayD  = ^ArrayD;
  pArrayI  = ^ArrayI;

  pArrayRR = ^ArrayRR;
  pArraySS = ^ArraySS;
  pArrayDD = ^ArrayDD;
  pArrayII = ^ArrayII;

{ Functions for allocating/deallocating single dimensional arrays. }
{                                                                  }
{ NRmax = maximum number of rows allocated/deallocated.            }
{ NCmax = maximum number of columns allocated/deallocated.         }

function NewArrayS(Nmax:Word):Pointer;

function DisposeArrayS(A:Pointer; Nmax:Word):Pointer;

function NewArrayD(Nmax:Word):Pointer;

function DisposeArrayD(A:Pointer; Nmax:Word):Pointer;

function NewArrayI(Nmax:Word):Pointer;

function DisposeArrayI(A:Pointer; Nmax:Word):Pointer;

function NewArrayR(Nmax:Word):Pointer;

function DisposeArrayR(A:Pointer; Nmax:Word):Pointer;

{ Functions for allocating/deallocating two dimensional arrays. }
{                                                               }
{ NRmax = maximum number of rows allocated/deallocated.         }
{ NCmax = maximum number of columns allocated/deallocated.      }

function NewArraySS(NRmax,NCmax:Word):Pointer;

function DisposeArraySS(A:Pointer; NRmax,NCmax:Word):Pointer;

function NewArrayDD(NRmax,NCmax:Word):Pointer;

function DisposeArrayDD(A:Pointer; NRmax,NCmax:Word):Pointer;

function NewArrayII(NRmax,NCmax:Word):Pointer;

function DisposeArrayII(A:Pointer; NRmax,NCmax:Word):Pointer;

function NewArrayRR(NRmax,NCmax:Word):Pointer;

function DisposeArrayRR(A:Pointer; NRmax,NCmax:Word):Pointer;

IMPLEMENTATION

{==============================================================================


function NewArray1D(Nmax:Word; DataSize:Integer):Pointer;

var
  MemP : Word;
  P    : Pointer;

begin
  MemP := (Nmax+1)*DataSize;
  If MaxAvail >= MemP then
    GetMem(P,MemP)
  else
    P := nil;
  NewArray1D := P;
end;

{==============================================================================


function DisposeArray1D(A:Pointer; Nmax:Word; DataSize:Integer):Pointer;

begin
  If A <> nil then
    begin
    FreeMem(A,(Nmax+1)*DataSize);
    DisposeArray1D := nil;
    end;
end;

{==============================================================================


function DisposeArray2D(A:Pointer; NRmax,NCmax:Word; DataSize:Integer):Pointer;

var
  I : Word;
  Q : ^ArrayPtr;

begin
  If A <> nil then
    begin
    Q := A;
    For I := 0 to NRmax do
      begin
      If Q^[I] <> nil then
        FreeMem(Q^[I],(NCmax+1)*DataSize);
      end;
    FreeMem(A,(NRmax+1)*PtrSize);
    DisposeArray2D := nil;
    end;
end;

{==========================================================================}


function NewArray2D(NRmax,NCmax:Word; DataSize:Integer):Pointer;

var
  Error : Boolean;
  I     : Word;
  MemP  : Word;        { Memory for pointers to each row of data }
  MemR  : Word;        { Memory for row of data                  }
  P     : ^ArrayPtr;

begin
  MemP := (NRmax+1)*PtrSize;
  If MaxAvail >= MemP then
    GetMem(P,MemP)
  else
    P := nil;
  If P <> nil then
    begin
    Error := false;
    MemR  := (NCmax+1)*DataSize;
    For I := 0 to NRmax do
      begin
      If MaxAvail >= MemR then
        GetMem(P^[I],MemR)
      else
        begin
        Error := true;
        P^[I] := nil;
        end;
      end;
    If Error then
      begin
      P := DisposeArray2D(P,NRmax,NCmax,DataSize);
      end;
    end;
  NewArray2D := P;
end;

{==========================================================================}


function NewArrayS(Nmax:Word):Pointer;

begin
  NewArrayS := NewArray1D(Nmax,SizeOf(Single));
end;

{==============================================================================


function DisposeArrayS(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayS := DisposeArray1D(A,Nmax,SizeOf(Single));
end;

{==============================================================================


function NewArrayD(Nmax:Word):Pointer;

begin
  NewArrayD := NewArray1D(Nmax,SizeOf(Double));
end;

{==============================================================================


function DisposeArrayD(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayD := DisposeArray1D(A,Nmax,SizeOf(Double));
end;

{==============================================================================


function NewArrayI(Nmax:Word):Pointer;

begin
  NewArrayI := NewArray1D(Nmax,SizeOf(Integer));
end;

{==============================================================================


function DisposeArrayI(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayI := DisposeArray1D(A,Nmax,SizeOf(Integer));
end;

{==============================================================================


function NewArrayR(Nmax:Word):Pointer;

begin
  NewArrayR := NewArray1D(Nmax,SizeOf(Real));
end;

{==============================================================================


function DisposeArrayR(A:Pointer; Nmax:Word):Pointer;

begin
  DisposeArrayR := DisposeArray1D(A,Nmax,SizeOf(Real));
end;

{==============================================================================


function NewArraySS(NRmax,NCmax:Word):Pointer;

begin
  NewArraySS := NewArray2D(NRmax,NCmax,SizeOf(Single));
end;

{==============================================================================


function DisposeArraySS(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArraySS := DisposeArray2D(A,NRmax,NCmax,SizeOf(Single));
end;

{==============================================================================


function NewArrayDD(NRmax,NCmax:Word):Pointer;

begin
  NewArrayDD := NewArray2D(NRmax,NCmax,SizeOf(Double));
end;

{==============================================================================


function DisposeArrayDD(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArrayDD := DisposeArray2D(A,NRmax,NCmax,SizeOf(Double));
end;

{==============================================================================


function NewArrayII(NRmax,NCmax:Word):Pointer;

begin
  NewArrayII := NewArray2D(NRmax,NCmax,SizeOf(Integer));
end;

{==============================================================================


function DisposeArrayII(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArrayII := DisposeArray2D(A,NRmax,NCmax,SizeOf(Integer));
end;

{==============================================================================


function NewArrayRR(NRmax,NCmax:Word):Pointer;

begin
  NewArrayRR := NewArray2D(NRmax,NCmax,SizeOf(Real));
end;

{==============================================================================


function DisposeArrayRR(A:Pointer; NRmax,NCmax:Word):Pointer;

begin
  DisposeArrayRR := DisposeArray2D(A,NRmax,NCmax,SizeOf(Real));
end;

END.


[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]