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?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Russell LibbySoftware 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
Metrix_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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.