[fpc-pascal] Dynamic arrays, yet another pitfall

Jürgen Hestermann juergen.hestermann at gmx.de
Sun Feb 9 15:34:25 CET 2014


There is another possible pitfall with dynamic arrays I trapped into which I would like to share.
Those who handle dynamic arrays in a virtuoso manner daily may skip this posting of course.
But I think for those who never used them before it may be of use.
Maybe it can be added to the Wiki (although again I had to make assumptions which may be wrong):



With the following declaration and code:

-------------------
var A,B: array of integer;
...
SetLength(A,10);
B := A;
SetLength(B,20);
-------------------

both variables A and B point to the same array with 20 Elements.
Changing A changes B and vice versa.
But a slight modification

-------------------
SetLength(A,0);
B := A;
SetLength(B,20);
-------------------

makes both variables A and B totaly decoupled! Although B is still assigned to be the same as A each variable is now a separate array with individual lengths and elements. Variable A has the length 0 and variable B is of length 20. Changing the length for one of them does no longer change the length of the other. If someone thinks about dynamic arrays as black boxes without the need to know the details because they are handled in the background then he will certainly be baffled by this.

Why is this so? Actually the variables A and B are just (4 byte) pointers to a structure which holds further information of the array (reference counter, length, pointer to the elements...). Setting the length of such a dynamic array to zero means that all data it pointed to will be freed and the pointer is set to NIL. Assigning this NIL-value to another variable of the same type sets this one to NIL too (after removing any potentially existing data of it). Changes for each of these variables no longer affect the other one because they do not point to the same structure anymore. Each has its own structure when adding elements with SetLength. This is especially a pitfall when the dynamic array is part of a complex structure and the reference to it should be given back by function or procedure parameters. It will work as long as the array has elements but fail when all elements have been (temporarily) removed!

Under the hood dynamic arrays are similar to pointers to records:

-------------------
type MyType = record
               ....
               end;
var A,B : ^MyType;
-------------------

After

-------------------
new(A);
B := A;
-------------------

B points to the same structure as A and changing A^ changed B^ too.
But after

-------------------
dispose(A);
A := nil;
B := A;
-------------------

A and B are both nil and

-------------------
new(A);
new(B);
-------------------

would create two different structures with each variable pointing to one of them. The same happens for dynamic arrays. Each length-command changes the structure where the pointer points to but when set to length zero it does not point to anything anymore (is NIL). Afterwards both variables are independend from another.

I think this is an important information about dynamic arrays which I was missing from the documentation.
Without this knowledge it can be hard to find subtle errors.





More information about the fpc-pascal mailing list