www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - two-dimensional C array and its analog in D

reply Alexandr Druzhinin <drug2004 bk.ru> writes:
Hello,
there is the following C function:

void foo(const void** data);

in C I can do:

int data[N][M];

data[0][0] = ..;
data[0][1] = ..;
data[1][0] = ..;
data[1][1] = ..;

foo(data); // for C code it works and in D code it doesn't (compile, but 
do nothing)

I've "solved" the problem like this:

int real_data[N*M];

real_data[0] = ..;
real_data[1] = ..;
real_data[2] = ..;
real_data[3] = ..;

int* data[N];
foreach(i; 0..N)
	data[i] = &real_data[i*M];

T.i. I form an array of pointers by myself without compiler so it 
doesn't seem to be good enough for some overcode and it looks dirty a 
little bit. Is there more suitable variant?

P.S. in few words I'd like to construct some D data structure that is 
binary compatible with two-dimensional C array (and do it in simple way, 
of course).
Aug 07 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/07/2012 11:07 PM, Alexandr Druzhinin wrote:
 Hello,
 there is the following C function:

 void foo(const void** data);

 in C I can do:

 int data[N][M];

 data[0][0] = ..;
 data[0][1] = ..;
 data[1][0] = ..;
 data[1][1] = ..;

 foo(data); // for C code it works and in D code it doesn't (compile, but
 do nothing)
This seems to work: import std.stdio; void main() { enum M = 3; enum N = 4; int[M][N] data; data[0][0] = 42; writeln(data); } The output: [[42, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] Ali
Aug 07 2012
parent reply Alexandr Druzhinin <drug2004 bk.ru> writes:
08.08.2012 12:13, Ali Çehreli пишет:
 This seems to work:

 import std.stdio;

 void main()
 {
      enum M = 3;
      enum N = 4;

      int[M][N] data;
      data[0][0] = 42;
      writeln(data);
 }

 The output:

 [[42, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

 Ali
I mean that I call C function from D code. And C function takes void** pointer as its argument. In C this means array of array, but if I pass D two-dimensional array it doesn't work (but compiles).
Aug 08 2012
parent "BLM768" <blm768 gmail.com> writes:
 I mean that I call C function from D code. And C function takes 
 void** pointer as its argument. In C this means array of array, 
 but if I pass D two-dimensional array it doesn't work (but 
 compiles).
I'm pretty sure that the issue is D's internal implementation of 2-dimensional arrays. From what I remember, if the arrays are defined as fixed-size, D creates just a single block of array data rather than creating pointers to pointers. OpenGL is expecting an array of pointers to 1-dimensional arrays, but D is giving it the pointer to the actual indices.
Aug 08 2012
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Alexandr Druzhinin:

 there is the following C function:

 void foo(const void** data);

 in C I can do:

 int data[N][M];

 data[0][0] = ..;
 data[0][1] = ..;
 data[1][0] = ..;
 data[1][1] = ..;

 foo(data); // for C code it works and in D code it doesn't 
 (compile, but do nothing)
That C code doesn't look correct, because the given data contains no pointers. Why don't you show us a complete compilable runnable correct tiny C program, that we have to translate to D? Bye, bearophile
Aug 08 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
 That C code doesn't look correct, because the given data 
 contains no pointers.
But this C code compiles: void foo(const void** data) {} int data[2][3]; int main() { foo(data); return 0; } Bye, bearophile
Aug 08 2012
parent reply Alexandr Druzhinin <drug2004 bk.ru> writes:
08.08.2012 16:29, bearophile пишет:
 That C code doesn't look correct, because the given data contains no
 pointers.
But this C code compiles: void foo(const void** data) {} int data[2][3]; int main() { foo(data); return 0; } Bye, bearophile
As I know in C an array is equal to pointer, so array of array == array of pointers == pointer to pointer == pointer to array. Correct me if I'm wrong. I'm trying to use OpenGL function glMultiDrawElements. It has signature: void glMultiDrawElements( enum mode, sizei *count, enum type, void **indices, sizei primcount ); If I declare indices like uint[][] indices; then code compiles but doesn't work (but it works in C). If I do as I described in the first post - it works in D. And I'd like to understand the reason of it. I think the reason is difference tween C array and D array, but I'm not sure. p.s. example of real code is too large to paste
Aug 08 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/08/2012 07:12 AM, Alexandr Druzhinin wrote:
 08.08.2012 16:29, bearophile пишет:
 That C code doesn't look correct, because the given data contains no
 pointers.
But this C code compiles: void foo(const void** data) {} int data[2][3]; int main() { foo(data); return 0; }
gcc does not accept that code: deneme.c:18920: error: passing argument 1 of ‘foo’ from incompatible pointer type deneme.c:18914: note: expected ‘const void **’ but argument is of type ‘int (*)[3]’
 As I know in C an array is equal to pointer,
In C and C++, an Array is automatically converted to a pointer to its first element.
 so array of array == array
 of pointers == pointer to pointer == pointer to array. Correct me if I'm
 wrong.

 I'm trying to use OpenGL function glMultiDrawElements. It has signature:
 void glMultiDrawElements(
 enum mode,
 sizei *count,
 enum type,
 void **indices,
 sizei primcount
 );
I looked at its online documentation: count is also an array that tells the lengths of individual rows of indices, right? So in reality the data is a dynamic ragged array? (I've never used that function before.)
 If I declare indices like
 uint[][] indices;
That's a slice of uint slices. Completely different memory layout than static arrays. In any case, I am pretty sure that what you need is the .ptr property of D arrays. You will have to make the 'indices' parameter dynamically by calling .ptr on the slices.
 then code compiles but doesn't work (but it works in C). If I do as I
 described in the first post - it works in D. And I'd like to understand
 the reason of it. I think the reason is difference tween C array and D
 array, but I'm not sure.

 p.s. example of real code is too large to paste
I've started writing the following but I don't know how you are calling the function. Can you get this to do what you expect in C: // WARNING: THIS C CODE DOES NOT COMPILE. #include <stdio.h> typedef size_t sizei; void glMultiDrawElements( /* enum mode,*/ sizei *count, /* enum type,*/ void **indices, sizei primcount) { for (size_t i = 0; i != primcount; ++i) { for (size_t j = 0; j != count[i]; ++j) { printf(" %d", indices[i][j]); } printf("\n"); } } int main() { /* Normally, the count array would be generated dynamically. */ int counts[4] = { 3, 3, 3, 3 }; int data[4][3]; data[0][0] = 42; data[2][2] = 43; glMultiDrawElements(counts, data, 4); } Ali -- D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html
Aug 08 2012
parent Alexandr Druzhinin <drug2004 bk.ru> writes:
08.08.2012 22:21, Ali Çehreli пишет:
 I looked at its online documentation: count is also an array that tells
 the lengths of individual rows of indices, right? So in reality the data
 is a dynamic ragged array? (I've never used that function before.)
Yes, it is.
  > If I declare indices like
  > uint[][] indices;

 That's a slice of uint slices. Completely different memory layout than
 static arrays.
Ok. I'll read about slices once again
 In any case, I am pretty sure that what you need is the .ptr property of
 D arrays. You will have to make the 'indices' parameter dynamically by
 calling .ptr on the slices.
.ptr works fine. if I do, for example so: uint[] firstSubArray; uint[] secondSubArray; uint*[] indicies; indicies[0] = firstSubArray.ptr; indicies[1] = secondSubArray.ptr; that is I manually form array of pointers. But I don't like it.
 I've started writing the following but I don't know how you are calling
 the function. Can you get this to do what you expect in C:

 // WARNING: THIS C CODE DOES NOT COMPILE.
 #include <stdio.h>

 typedef size_t sizei;

 void glMultiDrawElements(
      /* enum mode,*/
      sizei *count,
      /* enum type,*/
      void **indices,
      sizei primcount)
 {
      for (size_t i = 0; i != primcount; ++i) {
          for (size_t j = 0; j != count[i]; ++j) {
              printf(" %d", indices[i][j]);
          }
          printf("\n");
      }
 }

 int main()
 {
      /* Normally, the count array would be generated dynamically. */
      int counts[4] = { 3, 3, 3, 3 };

      int data[4][3];
      data[0][0] = 42;
      data[2][2] = 43;

      glMultiDrawElements(counts, data, 4);
 }
yes, it looks like what I mean, but I'm sleepy now :)
Aug 08 2012