Why use pointers to arrays?

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Why use pointers to arrays?

Graeme Geldenhuys-2
Hi,

The other "arrays" discussion got me thinking, and after working so
long with only desktop type applications that talk to database API's,
I long some knowledge of the lower lever Pascal features that was so
often used in Turbo Pascal days.

Anyway, I'm port an application that was written for OS/2 years ago
using SpeedPascal. I have already found quite a differences between
Free Pascal and SpeedPascal implementations of the "object pascal"
language.

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?


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;



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.

--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Florian Klämpfl
Graeme Geldenhuys schrieb:

>
>
> 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;

Because this array has a fixed size.

>
> Is there some advantage for using a pointer to the array, when passing
> it around between procedures and functions?
>
>
> 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;

A dynamic array does several magic behind your neck mainly taking care
of managed types. It depends on the code if it works or not.

>
>
>
> 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?

SetLength is a Borland extension. The code as shown is standard pascal
code. It's relative complexity simply shows why dyn. arrays were invented.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Andrew Brunner
In general I use pointers to data structures and especially when they
are arrays.

Take the following

PIntArray: ^TIntArray;

TIntArray:Array of Integer;


1st benefit:

declaring methods associated with classes before TIntArray needs to be
defined or declared.
  eg. procedure DoSomething(Var Data:TIntArray); vs (DataP:PIntArray);

Non-obvious benefit to all FPC users

FPC forces the ^ operator while accessing structures as pointers.
Delphi didn't force it and I even suspect that memory leaks can result
in NOT using the ^ to denote the reference to the pointer rather than
the pointer itself.

Lastly, passing by reference rather than by value is much faster.
Since copies need not be made when entering a method when entered
using a Pointer declaration vs DoSomething(Data:TIntArray).  In the
latter a copy of the calling Data array would be made, slowing the
application and using more memory - and for recursive methods lead to
the Stack running out of memory.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Graeme Geldenhuys-2
On 11/10/2009, Andrew Brunner <[hidden email]> wrote:
>  FPC forces the ^ operator while accessing structures as pointers.
>  Delphi didn't force it and I even suspect that memory leaks can result
>  in NOT using the ^ to denote the reference to the pointer rather than
>  the pointer itself.

This was just discussed in another thread. This is not always forced by FPC.
eg:

var
  S:  TMyArray;
  pS: ^TMyArray;

then use them as follows:

  S[2]
  pS[2]

Both work just fine without dereferencing the second line. Weird
behaviour, but true.


>  Lastly, passing by reference rather than by value is much faster.
>  Since copies need not be made when entering a method when entered

OK, so this is only a benefit then if you use Arrays. If I had to use
a simple data class (class with no methods), then I can simply pass it
as normal or via 'var' parameters and get the same result as you
mentioned.


--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Vinzent Höfler
In reply to this post by Andrew Brunner
Andrew Brunner <[hidden email]>:

> 1st benefit:
>
> declaring methods associated with classes before TIntArray needs to be
> defined or declared.
>   eg. procedure DoSomething(Var Data:TIntArray); vs (DataP:PIntArray);

Huh? Is there any difference other than the second one can take a NIL value?

> Lastly, passing by reference rather than by value is much faster.

That's what "const" has been invented for: Letting the compiler decide the most efficient way.

Not to mention, expressing your intent:

You don't change it, say so: "const".
You change it,       say so: "var".
You initialize it,   say so: "out".

If you just take the pointer no-one knows if the value is in/in out/or out. That's clearly not a "benefit".


Vinzent.
--
GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT!
Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Andrew Brunner
On Sun, Oct 11, 2009 at 5:25 PM, "Vinzent Höfler"
<[hidden email]> wrote:
> Andrew Brunner <[hidden email]>:
>
>> 1st benefit:
>>
>> declaring methods associated with classes before TIntArray needs to be
>> defined or declared.
>>   eg. procedure DoSomething(Var Data:TIntArray); vs (DataP:PIntArray);
>
> Huh? Is there any difference other than the second one can take a NIL value?

Read up on forward declarations.  The technique of declaring a typed
pointer to any data structure in FPC and Delphi was that you can use
it in fields and methods of objects and data structures w/o having to
actually have it fleshed out until later in the interface envelope of
the unit.   I've found that using forward declarations is a saving
grace with complicated systems.

>> Lastly, passing by reference rather than by value is much faster.
>
> That's what "const" has been invented for: Letting the compiler decide the most efficient way.

Oh I don't know about that one.  I'd like someone else to comment on
that.  Does using "const" prohibit copies of the memory.  I had memory
leaks with Delphi 5 or 6 doing this way back when and I attributed it
to trying to pass by reference using const... IMO it should do this
but may have had lead me to believe this is not the case...  But the
fact it that passing by reference is faster than passing by value...
That was my only point - which you made quite well.  As far as the
invention of const descriptor - I only use that for conventional
objects since dealing with pointers to data by const or by var is
trivial not organization or for maintanince or code review ;-)

> Not to mention, expressing your intent:
>
> You don't change it, say so: "const".
> You change it,       say so: "var".
> You initialize it,   say so: "out".
>
> If you just take the pointer no-one knows if the value is in/in out/or out. That's clearly not a "benefit".
>
Ahhh... The beauty of Pascal over C++ ;-)  Buy you're getting way to
particular man...  You know I've never had a need for Out save for
once. LOL.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Marc Weustink
In reply to this post by Graeme Geldenhuys-2
Graeme Geldenhuys wrote:

> On 11/10/2009, Andrew Brunner <[hidden email]> wrote:
>>  FPC forces the ^ operator while accessing structures as pointers.
>>  Delphi didn't force it and I even suspect that memory leaks can result
>>  in NOT using the ^ to denote the reference to the pointer rather than
>>  the pointer itself.
>
> This was just discussed in another thread. This is not always forced by FPC.
> eg:
>
> var
>   S:  TMyArray;
>   pS: ^TMyArray;
>
> then use them as follows:
>
>   S[2]
>   pS[2]
>
> Both work just fine without dereferencing the second line. Weird
> behaviour, but true.

However they have a different meaning.

assume TMyArray=array[1..10] of Byte;

then S[2] refers to the second element of S, being the second byte,
while pS[2] refers to the 3 element of pS, being the 3rd TMyArray


Marc

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Andrew Brunner
On Mon, Oct 12, 2009 at 12:43 PM, Marc Weustink <[hidden email]> wrote:
> Graeme Geldenhuys wrote:
>>
>> On 11/10/2009, Andrew Brunner <[hidden email]> wrote:
>>>
>>>  FPC forces the ^ operator while accessing structures as pointers.
>>>  Delphi didn't force it and I even suspect that memory leaks can result
>>>  in NOT using the ^ to denote the reference to the pointer rather than
>>>  the pointer itself.
>>  pS[2] <<<<<<<<<<<<<<<

Any idea what the compiler option is under Lazarus (that's what I use
exclusively)?

I get a compiler error when I don't use the ^ operator.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Henry Vermaak
2009/10/12 Andrew Brunner <[hidden email]>:
>>>  pS[2] <<<<<<<<<<<<<<<
>
> Any idea what the compiler option is under Lazarus (that's what I use
> exclusively)?
>
> I get a compiler error when I don't use the ^ operator.

It only works with {$mode delphi} and lazarus uses {$mode objfpc}, i think.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Vinzent Höfler
In reply to this post by Andrew Brunner
Andrew Brunner <[hidden email]>:

> On Sun, Oct 11, 2009 at 5:25 PM, "Vinzent Höfler"
>
> Read up on forward declarations.  The technique of declaring a typed
> pointer to any data structure in FPC and Delphi was that you can use
> it in fields and methods of objects and data structures w/o having to
> actually have it fleshed out until later in the interface envelope of
> the unit.   I've found that using forward declarations is a saving
> grace with complicated systems.

Oh, you're talking about what I call "incomplete type"? ;)

I always was under the impression that the pointed-to-type being declared must be completed in the same declaration section, has that changed? If not, I fail to see the benefit, because you still have to complete the type in the same scope. Which is technically the same as directly declaring it in the first place (unless it's self-referencing, of course).


Vinzent.
--
GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT!
Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Why use pointers to arrays?

Tomas Hajny
In reply to this post by Graeme Geldenhuys-2
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

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal