6

I am working on my school project and I would like to use Dynamic (not static) array. I worked with ObjectPascal, so I am used to some syntax. But now I am programming in the old TurboPascal (I am using Turbo Pascal 7 for Windows).

It doesn't seem to know the ObjectPascal, so I thought, that you Turbo Pascal doesn't know dynamic arrays.

Could anyone tell me, if my theory is right or not? I tried to google, but I was not succesfull. Basicly I am asking "how is it with dynamic arrays in Turbo Pascal 7" ? Thank you for all reactions.

  • You can achieve a "dynamic array" with pointers. Google for it. – darkl Feb 28 '17 at 21:29
  • 1
    TP7 did not have dynamic arrays like ObjectPascal in Delphi does. However, one trick in those days was to declare an array as say array[0..0] of integer, then use GetMem to allocate space for an array of whatever size you like and access it via a pointer. That may be what @darkl is thinking of. – MartynA Feb 28 '17 at 21:35
  • Yes, I found dynamic array with pointers, but I didn't like it at all, I was looking for more "elegant" way to do so. Thank you for you quick help. –  Feb 28 '17 at 21:58
  • Are you required to use TP7? – lurker Feb 28 '17 at 22:05
  • @lurker: TPW was 16-bit only and may be all the school is licensed for. – MartynA Feb 28 '17 at 22:13
  • Using pointers and GetMem for the dynamic size is more or less how Delphi does it. Difference is that you are required to free the memory, while Delphi can handle that with a built-in reference count when the variable goes out of scope. (And the element access hides the ^ indirection in Delphi). I'm still using TP7 with the pointer technique for dynamic arrays. – LU RD Feb 28 '17 at 23:11
  • 2
    @MartynA not sure why they wouldn't use Free Pascal. Or does the FPC license restrict educational use? – lurker Feb 28 '17 at 23:19
  • I dont see anything bad in turbopascal. In fact I am using it, because i like it more than freepascal. We can use both, as far as i know, freepascal is really free. Turbo pascal is more stable than freepascal. –  Mar 01 '17 at 22:40
  • Lurker: the FPC license does not restrict educational use, and is/was widely used in education. – Marco van de Voort Mar 02 '17 at 15:08
  • Turbo Pascal is only *more stable* because it was discontinued more than two decades ago. It certainly is as *stable* as it will ever be. But you pay the price for using that ancient technology, one of which is that you don't have the conveniences of more recent (e.g, less than 20 years ago) innovations like dynamic arrays. You want the old-style tools, you have to do the old-style work to use them. Can't have it both ways. – Ken White Mar 03 '17 at 00:55
  • Worse, while the stability and general trouble freeness of TP hasn't changed, often the same can't be said for the OS (emulation) layer it runs on top of. – Marco van de Voort Mar 09 '17 at 20:36

3 Answers3

8

As MartynA says, there is no dynamic array type in Turbo Pascal. You need to manually allocate memory using pointers, and be careful if you use rangechecks.

Typically you define an array type

TYPE
  TArrayT = array[0.. ((65535-spillbytes) div sizeof(T))-1] of T;

where spillbytes is a constant for a small deduction because you can't use the whole 64k, see what the compiler accepts. (Probably this deduction is for heapmanager structures inside the 64k block)

Then you define a pointer

  PArrayT= ^TArrayT;

and a variable to it

  var 
     P : PArrayT;
      

and you allocate nrelement elements using getmem;

 getmem(P,SizeOf(T) * nrelements);

and optionally fill them with zero to initialize them:

 fillchar(p^,SizeOf(T) * nrelements,#0);

You can access elements using

 p^[index]

to free them, use freemem using the exact opposite of the getmem line.

 freemem(P,Sizeof(T)*nrelements);

Which means you have to save the allocated number of elements somewhere. This was fixed/solved in Delphi and FPC.

Also keep in mind that you can't find bugs with rangechecking anymore.

If you want arrays larger than 64k, that is possible, but only with constraints, and it matters more which exact TP target (dos, dos-protected or Windows you use) I advise you to search for the online SWAG archive that has many examples. And of course I would recommend to go to FreePascal/Lazarus too where you can simply do:

 var x : array of t;
 begin
    setlength(x,1000000);

and be done with it without additional lines and forget about all of this nonsense.

Marco van de Voort
  • 25,628
  • 5
  • 56
  • 89
  • TP7 has objects, so the dynamic array type (for one type) could be wrapped in an object. That is what I would do. Hides all the ugly details and makes them pretty well usable. The object could have methods to access, e.g. `function Get(Index): Integer` and `procedure Put(Index, Value: Integer);`, etc. The initial length could be set in the constructor: `constructor Init(Len: Integer);`, etc.etc. – Rudy Velthuis Mar 11 '17 at 12:40
  • 1
    One could take the TP tcollection (which is more like Delphi TList than Delphi TCollection) and change it to integers. But either way is an investment in grossly outdated code, better to move to FPC where dynamic arrays even work in 16-bits dos apps. Still, I didn't want to be all negative so that's why there is this write up. But the mesage should be clear, don't invest in TP if you are going to do data centric coding. – Marco van de Voort Mar 11 '17 at 14:08
  • I agree that FPC is the far better choice. – Rudy Velthuis Mar 12 '17 at 17:49
2

I'm using Turbo Pascal 5.5 and to create a dynamic array, perhaps the trick is to declare an array with zero dimension as follows:

dArray = array [0..0] of integer;

And then declare a pointer to that array:

pArray = ^dArray ;

And finally, create a pointer variable:

ArrayPtr : pArray;

You can now reference the pointer variable ArrayPtr as follows:

ArrayPtr^[i]; { The index 'i' is of type integer}

See the complete example below:

{
  Title: dynarr.pas

  A simple Pascal program demonstrating dynamic array.

  Compiled and tested with Turbo Pascal 5.5.
}

program dynamic_array;


{Main Program starts here}
type
  dArray = array [0..0] of integer;
  pArray = ^dArray ;
var
  i : integer;
  ArrayPtr : pArray;
begin

  for i := 0 to 9 do { In this case, array index starts at 0 instead of 1. }
    ArrayPtr^[i] := i + 1;

  writeln('The Dynamic Array now contains the following:');
  writeln;

  for i := 0 to 9 do
    writeln(ArrayPtr^[i]);

end.

In this example, we have declared the array as:

array[0..0] of integer;

Therefore, the index starts at 0 and if we have n elements, the last element is at index n-1 which is similar to array indexing in C/C++.

Regular Pascal arrays start at 1 but for this case, it starts at 0.

Andre Hofmeister
  • 3,185
  • 11
  • 51
  • 74
  • I had to try this - whipped out TP7, DOSBox, typed in the code, compiled and ran. And just an FYI, dArray can be any range as long as start and end are the same, [1..1] (helping the Pascal guys keep it 1 based, of course update your for loop(s)). – Ozz Nixon Oct 13 '18 at 16:26
0
unit Vector;

interface

const MaxVector = 8000;
  // 64 k div SizeOf(float); number of float-values that fit in 64 K of stack
  VectorError: boolean = False;
// toggle if error occurs. Calling routine can handle or abort


type
  VectorStruc = record
    Length: word;
    Data: array [1..MaxVector] of float;
  end;
  VectorTyp = ^VectorStruc;

procedure CreateVector(var Vec: VectorTyp; Length: word; Value: float);
{ Generates a vector of length Length and sets all elements to Value }

procedure DestroyVector(var Vec: VectorTyp);
{ release memory occupied by vector }

procedure SetVectorElement(var Vec: VectorTyp; n: word; c: float);

function GetVectorElement(const Vec: VectorTyp; n: word): float;

implementation

var ch: char;

function WriteErrorMessage(Text: string): char;

begin
  Write(Text);
  Read(WriteErrorMessage);
  VectorError := True;         // toggle the error marker
end;

procedure CreateVector(var Vec: VectorTyp; Length: word; Value: float);

var
  i: word;

begin
  try
    GetMem(Vec, Length * SizeOf(float) + SizeOf(word) + 6);
  except
    ch := WriteErrorMessage(' Not enough memory to create vector');
    exit;
  end;
  Vec^.Length := Length;
  for i := 1 to Length do
    Vec^.Data[i] := Value;
end;

procedure DestroyVector(var Vec: VectorTyp);

var
  x: word;

begin
  x := Vec^.Length * SizeOf(float) + SizeOf(word) + 6;
  FreeMem(Vec, x);
end;

function VectorLength(const Vec: VectorTyp): word;

begin
  VectorLength := Vec^.Length;
end;

function GetVectorElement(const Vec: VectorTyp; n: word): float;

var
  s1, s2: string;

begin
  if (n <= VectorLength(Vec))  then
    GetVectorElement := Vec^.Data[n]
  else
  begin
    Str(n: 4, s1);
    Str(VectorLength(Vec): 4, s2);
    ch := WriteErrorMessage(' Attempt to read non-existent vector element No ' +
      s1 + ' of ' + s2);
  end;
end;


procedure SetVectorElement(var Vec: VectorTyp; n: word; C: float);

begin
  if (n <= VectorLength(Vec))  then
    Vec^.Data[n] := C
  else
    ch := WriteErrorMessage(' Attempt to write to non-existent vector element');
end;

end.  

As long as your data fit on the stack, i.e., are smaller than 64 kB, the task is relatively simple. The only thing I don't know is where the 6 bit of extra size go, they are required, however.