PDA

View Full Version : Pointer to ARRAY in Delphi



Ñuño Martínez
15-11-2007, 01:39 PM
System: Windows
Compiler/IDE: Lazarus & Delphi (trying multiplatform)
libraries: RTL

I'm using a DLL written in C. This library has several functions that use arrays. C uses pointers in most cases so I did something like this:PROGRAM example;
TYPE
TLISTptr = ^TLIST;
TLIST = RECORD
Field: INTEGER;
Other: INTEGER;
END;

FUNCTION get_list: TLISTptr; CDECL; EXTERNAL 'lib.dll';

VAR
TheList: TLISTptr;
BEGIN
{ Somewhere }
TheList := get_list;
WriteLn (TheList[0]);
END.That compiles and runs perfect using Free Pascal but some users tells me that Delphi can't compile it. So I changed it by this:PROGRAM example;
TYPE
TLIST_ITEMptr = ^TLIST_ITEM;
TLIST_ITEM = RECORD
Field: INTEGER;
Other: INTEGER;
END;

TLISTptr = ^TLIST;
TLIST = ARRAY OF TLIST_ITEM;

FUNCTION get_list: TLISTptr; CDECL; EXTERNAL 'lib.dll';

VAR
TheList: TLISTptr;
BEGIN
{ Somewhere }
TheList := get_list;
WriteLn (TheList^[0]);
END.Free Pascal compiles it but it returns a runtime 216 error. No idea about Delphi.

By the way this code seems to work both Delphi and FPC:PROGRAM example;
TYPE
TLIST_ITEMptr = ^TLIST_ITEM;
TLIST_ITEM = RECORD
Field: INTEGER;
Other: INTEGER;
END;

TLISTptr = ^TLIST;
TLIST = ARRAY [0..80] OF TLIST_ITEM;

FUNCTION get_list: TLISTptr; CDECL; EXTERNAL 'lib.dll';

VAR
TheList: TLISTptr;
BEGIN
{ Somewhere }
TheList := get_list;
WriteLn (TheList^[0]);
END.But the returned list size may vary from 1 to infinite, so this isn't the solution

¬øAlny idea about how to work with a non-sized array pointer in Delphi?

Thanks

Ñuño Martínez
15-11-2007, 02:02 PM
I've found the answer from another forum.

PROGRAM example;
TYPE
TLIST_ITEMptr = ^TLIST_ITEM;
TLIST_ITEM = RECORD
Field: INTEGER;
Other: INTEGER;
END;

TLISTptr = ^TLIST;
TLIST = ARRAY [0..0] OF TLIST_ITEM;

FUNCTION get_list: TLISTptr; CDECL; EXTERNAL 'lib.dll';

VAR
TheList: TLISTptr;
BEGIN
{ Somewhere }
TheList := get_list;
WriteLn (TheList^[0]);
END.Note the use of [ 0..0 ] to prevent 'unfair use'.

It was sooooooo obvious... I'm embarassed... :oops:

JernejL
15-11-2007, 05:35 PM
@array is NOT SAME as @array[0] or @array[0, 0], it is simply not, just like string[0] is something else, for arrays you need to point your pointer AT THE DATA, NOT at the variable itself, the structure of the variable is not guaranteed to be same on all compilers, but the DATA is, so point at the data and not at the variable, because variable may contain internal structures to reprisent and hold the actual data.

If you have a dynamic 2d array of integers the data is not even guaranteed to be contigous, there may be internal data between each row of these arrays, not delphi not fpc or any other pascal compiler will guarantee that @array would ever point to data itself and the contigoucy of dynamic array internal structures.

User137
15-11-2007, 07:35 PM
By the way this code seems to work both Delphi and FPC:PROGRAM example;
TYPE
TLIST_ITEMptr = ^TLIST_ITEM;
TLIST_ITEM = RECORD
Field: INTEGER;
Other: INTEGER;
END;

TLISTptr = ^TLIST;
TLIST = ARRAY [0..80] OF TLIST_ITEM;

FUNCTION get_list: TLISTptr; CDECL; EXTERNAL 'lib.dll';

VAR
TheList: TLISTptr;
BEGIN
{ Somewhere }
TheList := get_list;
WriteLn (TheList^[0]);
END.But the returned list size may vary from 1 to infinite, so this isn't the solution

¬øAlny idea about how to work with a non-sized array pointer in Delphi?

Thanks
Wait, first you say "returned list size" but then you are asking to work with non-sized? How do you find out size of this list?

Even this should work and reserve same space as 0..0 when using it through pointers, but this allows compiler to access up to item[255] manually, where 0..0 only allows for [0] or through variable because of range checking:
TLIST = ARRAY [0..255] OF TLIST_ITEM;

dmantione
15-11-2007, 08:14 PM
0..0 (with range checks disabled!!!) is the best solution. Delphi has no facilities for unbounded arrays.

Jimmy Valavanis
16-11-2007, 06:21 AM
ry to declare TLISTptr as a pointer to array of TLIST items.

For example: (not tested)



PROGRAM example;
TYPE
TLIST = RECORD
Field: INTEGER;
Other: INTEGER;
END;
TLISTARRAY = array[0..$FFFF] of TLIST;
TLISTptr = ^TLISTARRAY;

FUNCTION get_list: TLISTptr; CDECL; EXTERNAL 'lib.dll';

VAR
TheList: TLISTptr;
BEGIN
{ Somewhere }
TheList := get_list;
WriteLn (TheList[0]);
END.

JSoftware
16-11-2007, 10:43 AM
Try to declare TLISTptr as a pointer to array of TLIST items.

For example: (not tested)



If that's going to work then you need to dereference the list pointer before indexation: ...^[0]

Ñuño Martínez
16-11-2007, 08:02 PM
Wait, first you say "returned list size" but then you are asking to work with non-sized? How do you find out size of this list?
Well, I think the problem is that I'm not a native English speaker. I wanted to say "returned list with size"? not sure.

Anyway thanks for the comments.

I would use:PROGRAM example;
TYPE
TLIST_ITEMptr = ^TLIST_ITEM;
TLIST_ITEM = RECORD
Field: INTEGER;
Other: INTEGER;
END;

TLISTptr = ^TLIST;
TLIST = ARRAY [0..0] OF TLIST_ITEM;

FUNCTION get_list: TLISTptr; CDECL; EXTERNAL 'lib.dll';

VAR
TheList: TLISTptr;
BEGIN
{ Somewhere }
TheList := get_list;
{$R-} { Don't check range. }
WriteLn (TheList^[0]); { Deference the pointer. }
{$R+}
END.Is that correct?

Weps
23-11-2007, 10:11 PM
0..0 (with range checks disabled!!!) is the best solution. Delphi has no facilities for unbounded arrays.


Type
TListItem = record
a,b,c: integer;
End;
TListArray = array of TListItem;


Doh!

dmantione
23-11-2007, 11:32 PM
That is not an unbounded array, but a dynamic array. Stored on the heap, therefore not usefull in many circumstances.

Weps
24-11-2007, 01:01 AM
Maybe your definition of unbounded is different from what I've learned, please enlighten me.

dmantione
24-11-2007, 08:18 AM
Simply take a look at ?ëu?±o's request, you have a pointer to an array with (at compile time) an unknown amount of array elements in memory. You cannot use a dynamic array, since a dynamic array tries to allocate an array dynamically on the heap.

Weps
24-11-2007, 12:43 PM
I don't know where you got your information but it is wrong.

There are two types of arrays, one where at compile time is known how many elements are in it (bounded) and one where you do not (unbounded).

In Delphi (Pascal) the second one is also referred to as a dynamic array, dynamic in the sense that the bounds (number of elements) can change at runtime.

In delphi, bounded arrays are declared as "array[a..b] of" where a <= b
and unbounded (dynamic) array as "array of".

The problem that the OP has, is that the declaration for unbounded arrays is different in c and Delphi, thus an unbounded array in c (simply a pointer) does not match an unbounded array in delphi (an actual TYPE).


type
PElement = ^TElement;
TElement = record
...
End;

procedure DoSomething;
var
FirstElement: PElement;
begin
// fetch array
FirstElement := get_list;

// loop
For K := 1 to NumberOfElementsInArray do Begin
...
Inc( FirstElement);
End;
End;


The obvious thing here is that "get_list" doesn't tell you how many elements are in the list, which can cause/cause a lot of bugs. (That's why they made a "dynamic array" type in Delphi....)

Robert Kosek
24-11-2007, 01:13 PM
And you don't understand that the count for the items is easily returned through an out parameter to get_list. Either way is perfectly valid. This isn't Python with "only one way to write things," this is Pascal.

Weps
24-11-2007, 02:22 PM
And you don't understand that the count for the items is easily returned through an out parameter to get_list. Either way is perfectly valid. This isn't Python with "only one way to write things," this is Pascal.

Did I write "I don't understand how to get the count for the items?"

Robert Kosek
24-11-2007, 03:20 PM
No, you were too busy digging yourself a pit. You aren't very helpful when you come out with a "you don't know anything" attack like you did.

Delphi does not, most emphatically not, support unbounded arrays! If you use a dynamic array you aren't "unbounded" but rather moving the bounds each and every time you resize the array. Believe me, just try doing a few million resizes in both directions and timing it against mere array modification (same number of items). It is not unbounded. Dynamically bounded and very useful, but not unbounded. While what you give does work so does Nuno's.

Weps
24-11-2007, 04:03 PM
I'm not attacking anybody, I merely get a bit ticked off when I see untrue statements. And I get a bit upset when I see people telling others to just go mess with compiler settings to achieve a result. Now that's helpful.

Anyways, just show me the definition of "unbounded arrays", in english. I already showed you what I think it is.

dmantione
24-11-2007, 06:59 PM
In Delphi (Pascal) the second one is also referred to as a dynamic array, dynamic in the sense that the bounds (number of elements) can change at runtime.


Exactly. It can change at runtime, but there is an upper bound. For an unbounded array, no information exists about its bounds, not at compile time not at runtime.

tpascal
24-11-2007, 07:12 PM
Mister Weps, yes it is true that dynamic arrays are used for using array with variable sizes at run time, however when you define the size using length(array,numelements) then Delphi (or what ever pascal compiler) will allocate that numelements size memory and will store a pointer and reference count; but the original problem is about how accesing elements into a block memory already allocated inside a C dll.

So you have a DLL which allocate internally an array and it returns a pointer to the first element, how you access in delphi easily more elements?, you cant just define a dinamic array in the delphi side, set the same length as the dll array and overwrite it with the returned pointer, (you will have a leek!);

so actually, after analizing the problem i think that



0..0 (with range checks disabled!!!) is the best solution. Delphi has no facilities for unbounded arrays.


looks best solution to me too.

tp.

Ps.
Indee i dont see neither in the original code where it is returned the amount elements allocated by the DLL, probably in a different call.