[fpc-pascal] Why use pointers to arrays?

Tomas Hajny XHajT03 at mbox.vol.cz
Mon Oct 12 22:47:17 CEST 2009


On 11 Oct 09, at 10:38, Graeme Geldenhuys wrote:

Hi,

 .
 .
> Anyway to get to my questions, and using the code snippets shown
> below. This code is all based on the code I am porting from
> SpeedPascal. So maybe some strange usage is simply due to the age of
> SpeedPascal etc..
> 
> 
> ----------------------
> Type
>   TLayoutLine = record
>     Text: PChar;
>     Length: longint;
>     Height: longint;
>     Width: longint;
>     MaxDescender: longint;
>     MaxTextHeight: longint;
>     LinkIndex: longint;
>     Style: TTextDrawStyle;
>     Wrapped: boolean;
>   end;
> 
> 
>   TLinesArray = array[ 0..0 ] of TLayoutLine;
> --------------------------
> 
> 
> 1)  Why would you use a pointer to an array and not simply a variable
> what IS the array? In the program I am porting the following field
> variable is defined.
> 
>   FLines: ^TLinesArray;
> 
> Why couldn't I simply say:
> 
>   FLines: TLinesArray;
> 
> Is there some advantage for using a pointer to the array, when passing
> it around between procedures and functions?

Yes, there's at least one - you cannot pass (or receive) nil if you 
use the array directly. Sometimes the API (e.g. OS API) needs the 
possibility to pass or receive nil.


> 2) The TLinesArray is a dynamic array, so shouldn't I maybe change the
> ported code to define the array as follows, instead of the [0..0]
> idea?
> 
>   TLinesArray = array of TLayoutLine;

Well, it is not a dynamic array strictly speaking, because dynamic 
arrays maintain number of elements as part of their definition, 
whereas in this case number of elements is kept elsewhere.


> 3) Maybe the strange usage (to me at least) of dynamic arrays could be
> explain in how the original program allocates memory for the array. In
> the class where FLines is defined, it initially reserves ten empty
> elements for the array in the class constructor.
> 
>   FAllocatedNumLines := 10;
>   GetMem( FLines, FAllocatedNumLines * sizeof( TLayoutLine ) );
> 
> And then later if it needs more space for elements, it redefines the
> array elements as follows:
> 
> Procedure TRichTextLayout.AddLineStart( Const Line: TLayoutLine );
> var
>   NewAllocation: longint;
> begin
>   if FNumLines >= FAllocatedNumLines then
>   begin
>     // reallocate the array twice the size
>     NewAllocation := FAllocatedNumLines * 2;
>     FLines := ReAllocMem(FLines, NewAllocation * sizeof(TLayoutLine));
>     FAllocatedNumLines := NewAllocation;
>   end;
>   FLines^[ FNumLines ] := Line;    //  ***** (1)
>   inc( FNumLines );
> end;
> 
> 
> Like I said, maybe this is related to different implementations of
> object pascal. By doesn't one allocate memory (array elements) via the
> SetLength() procedure?
> eg:
> 
>   FAllocatedNumLines := 10;
>   SetLength( FLines^, FAllocatedNumLines);
> 
> 
> I marked on of the lines above with (1). I sometimes get "out of
> range" errors there, so clearly somewhere in all this dereferencing of
> arrays etc, I probably made a mistake somewhere in porting/translating
> the SpeedPascal code to Free Pascal.

Not really, you just use range checking whereas the original code 
doesn't. The type definition specifies an array with exactly one 
element [0..0], but you access more elements using that type 
definition. Technically, there are several ways for such type 
definitions, but all of them imply that range checking cannot be used 
any longer. The first one is this one. The second would be defining 
the upper bound as some very high value (at best as the highest 
possible, but even that varies e.g. between 16-bit, 32-bit and 64-bit 
CPUs, so it's not portable easily, and it doesn't give you any range 
checking either, because although type allows many elements, the real 
content has fewer elements and the compiler doesn't know how many). 
The third option (using the pointer mathematics and not available in 
older Pascal compilers) is declaring the pointer as a pointer to a 
single element of that array and accessing it as P[x] (without 
dereferencing this pointer; I'd personally tend to use P[x]^, but 
that doesn't work, i.e. in this case the pointer isn't a pointer any 
longer ;-) ).

Tomas




More information about the fpc-pascal mailing list