Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Be warned that in Delphi, a dynamic array is not exactly the same as a static array.</p> <p>A static array is defined as such:</p> <pre><code>type TIntegerArray10 = array[0..10] of integer; PIntegerArray10 = ^TIntegerArray10; </code></pre> <p>And a dynamic array is defined as:</p> <pre><code>type TIntegerDynamicArray = array of integer; </code></pre> <p>But the dynamic array memory is allocated on the heap by Delphi, using the SetLength() function. You can access to the highest boundary with Length() or High() functions.</p> <p>The dynamic array can then be mapped back to a static array, via the pointer() function:</p> <pre><code>var Dyn: TIntegerDynamicArray; i: integer; begin SetLength(Dyn,11); // will create Dyn[0] to Dyn[10] for i := 0 to high(Dyn) do begin // same as for i := 0 to length(Dyn)-1 do Dyn[i] := i; assert(PIntegerArray(pointer(Dyn))^[i]=i); end; end; </code></pre> <p>The char * (pointers of char) can be handled as array of char in Delphi, but it's not the most easy way of doing it, because you'll have to get and free the memory at hand. You can use the AnsiString type, then cast it as a pointer: it will return a PAnsiChar.</p> <p>So for an array of AnsiString, each array item (accessible by []) will be a PAnsiChar, and the pointer to the whole array of AnsiString will be a PPAnsiChar, i.e. a char **</p> <pre><code>var Dyn: array of AnsiString; begin SetLength(Dyn,19); for i := 0 to 19 do Dyn[i] := IntToStr(i); // now pointer(Dyn) can be mapped to PPAnsiChar or char ** end; </code></pre> <p>All this is useful to create some content from Delphi, then use it in your C code.</p> <p>For the contrary, i.e. using C generated char ** into Delphi, you must use pointers to static arrays, not pointer to dynamic arrays. As far as I remember, char ** structures usually end with a NULL to mark the end of array.</p> <p>Here is what I would recommend to use, to convert a C char ** array into a true Delphi dynamic array (to be adapted to your purpose):</p> <pre><code>type TAnsiStringDynArray = array of AnsiString; TPAnsiCharArray = array[0..maxInt div 4-1] of PAnsiChar; PPAnsiCharArray = ^TPAnsiCharArray; procedure ConvertCToDelphi(inArray: PPAnsiCharArray; var outDynArray: TAnsiStringDynArray); var i, n: integer; begin n := 0; if inArray&lt;&gt;nil then while inArray[n]&lt;&gt;nil do inc(n); SetLength(outDynArray,n); for i := 0 to n-1 do outDynArray[i] := AnsiString(InArray[n]); // explicit typing to make Delphi 2009 happy end; </code></pre> <p>You can use PPAnsiChar, if you just want to enumerate a char ** array:</p> <pre><code>procedure Test(FromC: PPAnsiChar); begin if FromC&lt;&gt;nil then while FromC^&lt;&gt;nil do begin writeln('Item value is ',FromC^); // Delphi will map FromC^ PAnsiChar into a string inc(FromC); // this will go to the next PAnsiChar in the array end; end; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. COYou have to be careful when doing memory manipulations with dynamic arrays outside Delphi. Dynamic arrays are like pointers to a static array with 2 more values (reference count and high) stored _before_ the beginning of the array data. So: 1) your C code should increment the reference count and decrement it when it doesn't need the array anymore; 2) changing the Delphi array's length in place using C (realoc) could lead to unexpected results; 3) if it is a dynarray of interfaces, variants or strings, then extra care should be taken as those types have magic compiler handling of it's refcount.
      singulars
    2. CO4) with the reference count mechanism there could be even more trouble as you could actually need to test if the refcount is zero and then _free the array when needed inside your C code_, else you may leak memory. A macro could be used to handle 1) and 4) easily tho.
      singulars
    3. CO@Trinidad: both points are true, theoretically. But in practice, I'll think that the C routines should make a copy of the given data if they need this data after they return to the Delphi code. In most cases, the C routine will consume the Delphi data, then return some results about the process. It's how SQLite3 works, and it's a common practice for libraries. So it's safe to call C code from Delphi, then let the reference count mechanism free the data when the variable is out of scope.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload