C Multidimensional arrays and Delphi

How can I pass a Delphi Multidimensional array to a C function that has the following declaration?

int Teste(int **v, int l, int c)

I know that Delphi and C have different Multidimensional arrays memory organizations. But I could not find any resource explaining clearly how can I bypass that.

Thanks
Mauricio.


MauricioMaiaAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
Metrix_Connect With a Mentor Commented:
Delphi

Static array types
A static array is stored as a contiguous sequence of variables of the component type of the array. The components with the lowest indexes are stored at the lowest memory addresses. A multidimensional array is stored with the rightmost dimension increasing first.
(Ref: http://info.borland.com/techpubs/delphi/delphi5/oplg/memory.html)

ANSI C (and C++ i believ)

Multidimensional Arrays
Multidimensional arrays are simply arrays of arrays (of arrays of arrays...)
A multidimensional array like m[3][2] is stored in consecutive memory locations as m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1]

So if you are using a Static interger array you should simply be able to pass the delphi array into the C function by typecasting the array to a pointer.

NOTE: In C teh int **V is just a pointer to a memory location, which is the first integer in the array

Here is some sample delphi code with a C like function i wrote to test this

type
  INTARRAY = ^integer;   // int *
  PINTARRAY = ^INTARRAY; // int **

// Test function to simulate a C style multidimesional integer array
// int Teste(int **v, int l, int c)
function Teste(v : PINTARRAY; cols : integer; rows : integer) : integer; stdcall;
var
  idxC, idxR : integer;
  memAddr : integer;
  value : integer;
begin
  for idxR := 0 to Rows - 1 do
    for idxC := 0 to Cols - 1 do
    begin
      //start + (y * width) + x;      width := sizeof(integer) * x)
      memAddr := integer(v) + (idxR * (sizeof(integer) * cols)) + (idxC * 4);
      value := INTARRAY(memAddr) ^;
      Form1.Memo1.Lines.Add(inttostr(value));
    end;

    result := 0;
end;


procedure TForm1.Button2Click(Sender: TObject);
const
  COLCOUNT = 10;
  ROWCOUNT = 5;
var
  col : integer;
  row : integer;
  aryDelphi : array[0..COLCOUNT - 1,0..ROWCOUNT - 1] of integer; // [cols, rows]
begin

  //Fill in the array values
  for row := 0 to 4 do
  begin
    for col := 0 to 9 do
    begin
      aryDelphi[col][row] := (col * 5) + row;
    end;
  end;

  //I have assumed the Teste function will loop through the array using l and c
  // as the cols and orws value, in this case 10 columns by 5 rows
  Teste(@aryDelphi, COLCOUNT, ROWCOUNT);
end;


Hope it helps

Richard Owen
0
 
Russell LibbyConnect With a Mentor Software Engineer, Advisory Commented:
Mauricio,

The following will allow you to allocate a 2 dimensional integer array that can be passed to the C function. You didn't specifiy the number of dimensions, but looking at the Tests function, I made the assumtion that it was 2.

// The declaration
//
// type declarator [<constant-expression>]
//
// declares an array composed of elements of type. An array consists of a
// contiguous region of storage exactly large enough to hold all of its elements.
// If an expression is given in an array declarator, it must evaluate to a
// positive constant integer. The value is the number of elements in the
// array. Each of the elements of an array is numbered from 0 through the
// number of elements minus one.
//
// Multidimensional arrays are constructed by declaring arrays of array type.
//

type
  IntegerArray      =  Array [0..Pred(MaxInt shr 4)] of Integer;
  PIntegerArray     =  ^IntegerArray;
  TMDIntegerArray   =  Array [0..Pred(MaxInt shr 4)] of PIntegerArray;
  PMDIntegerArray   =  ^TMDIntegerArray;

function CreateMDIntArray(Rows, Cols: Integer): PMDIntegerArray;
var  dwIndex:    Integer;
begin

  // We will allocate one more row than required (AND leave it null). This will
  // allow us to free the array without knowing the actual number of rows
  result:=AllocMem(Succ(Rows) * SizeOf(PIntegerArray));

  // Allocate memory for each row (except the last)
  for dwIndex:=0 to Pred(Rows) do result^[dwIndex]:=AllocMem(Cols * SizeOf(Integer));

end;

procedure FreeMDIntArray(MDIntArray: PMDIntegerArray);
var  dwIndex:    Integer;
begin

  // Set starting index
  dwIndex:=0;

  // Walk the rows until null is reached
  while Assigned(MDIntArray^[dwIndex]) do
  begin
     FreeMem(MDIntArray^[dwIndex]);
     Inc(dwIndex);
  end;

  // Free the array
  FreeMem(MDIntArray);

end;

var  pmdaTest:      PMDIntegerArray;
begin

  // Create the multidimensional array
  pmdaTest:=CreateMDIntArray(10, 5);

  // Set [5, 0] to = 100
  pmdaTest^[5]^[0]:=100;

  // Pass the array to the teste function (used 5 and 0 for the other params, just for example)
  Teste(pmdaTest, 5, 0);

  // Free the array
  FreeMDIntArray(pmdaTest);

end;

---

Hope this helps,
Russell


0
All Courses

From novice to tech pro — start learning today.