www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Question about arrays

reply "Stephen Jones" <siwenjo gmail.com> writes:
My C programming lies in cobwebs but from memory an array was a 
pointer to the zeroth index of a set of uniformly sized chunks of 
memory. I am perplexed to find that in D a call to an array (of 
float vertices for example) cannot be accomplished by handing &v 
to functions that need the zeroth index. Is this because D holds 
a pointer to an array object and the zeroth index is accessed 
(via compiler background work) to  &v[0]?
Apr 21 2012
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/21/2012 03:05 PM, Stephen Jones wrote:
 My C programming lies in cobwebs but from memory an array was a pointer
 to the zeroth index of a set of uniformly sized chunks of memory.

Yes and no. :) What you are describing is the feature where an array decays to what you describe. But there is also the concept of array in C, which is a collection of elements side by side. When you apply sizeof to such a thing, you get the size of the whole thing. So, the whole thing is the array. But you are right, when passed to functions, they decay to "pointer to first element."
 I am
 perplexed to find that in D a call to an array (of float vertices for
 example) cannot be accomplished by handing &v to functions that need the
 zeroth index. Is this because D holds a pointer to an array object and
 the zeroth index is accessed (via compiler background work) to &v[0]?

In D, arrays are what they should have been in C :). A pointer and a size. Something the equivalent of the following (for the int type): struct int_Array { int * elements; size_t number_of_elements; } Correction: That is a slice (aka dynamic array). There is also the fixed-length arrays (aka static arrays) in D. If you pass the address of a slice, you are passing the address of such a struct variable. So don't bother with the address at all, just pass the array object by value. Ali
Apr 21 2012
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/22/12, Stephen Jones <siwenjo gmail.com> wrote:
 My C programming lies in cobwebs but from memory an array was a
 pointer to the zeroth index of a set of uniformly sized chunks of
 memory. I am perplexed to find that in D a call to an array (of
 float vertices for example) cannot be accomplished by handing &v
 to functions that need the zeroth index. Is this because D holds
 a pointer to an array object and the zeroth index is accessed
 (via compiler background work) to  &v[0]?

D array -> struct of a length and pointer to the first element. If you want to pass arrays to C functions you can do either of these: float[] arr; cFunc(arr.ptr, arr.length) cFunc(&arr[0], arr.length); I'm assuming the C function needs a length. Maybe this will make things clearer: void main() { int[] a = new int[](10); size_t count = *cast(size_t*)&a; // first element is the count assert(count == 10); a[0] = 5; a[1] = 100; int* iter = &a[0]; // or use a.ptr assert(*iter == 5); ++iter; assert(*iter == 100); } Of course you wouldn't really use this style of code in D, but if you have to pass arrays to C use the .ptr field or &arr[0]. On the other hand, passing jagged multidimensional arrays via .ptr to C functions isn't going to work out of the box, but that's another topic (and there's a workaround). A good article about D arrays/slices is here: http://dlang.org/d-array-article.html
Apr 21 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/22/2012 03:17 PM, Stephen Jones wrote:
 Thanks for the replies. I am still uncertain about something. The
 documentation distinguishes between dynamic slices (int[5] a = new
 int[5])

The documentation may be incorrect because int[5] is never a slice. It is a fixed-length array. As an aside, I don't like calling fixed-length arrays static arrays, because static implies compile time. Fine, the length is known at compile time but as your code above demonstrates, the storage can be allocated at runtime, dynamically.
 which are managed by the runtime, and stack allocated arrays
 (int[5] b).

"Stack allocated" may also be misleading because a fixed-length array can be a part of a type that is allocated dynamically: class Foo { int[5] b; // <-- not on the stack } As jerro explained, a slice is a pointer to the first element and a length. A fixed-length array is N elements side by side.
 My confusion is, if the syntax for both stack based and managed memory
 arrays is the same (&v[0] or &v.ptr)

You must have meant &v[0] and v.ptr. It is the same for both types: // fixed-length { int[5] a = new int[5]; auto firstElem_1 = a.ptr; auto firstElem_2 = &a[0]; assert(firstElem_1 == firstElem_2); } // slice { int[] a = new int[5]; auto firstElem_1 = a.ptr; auto firstElem_2 = &a[0]; assert(firstElem_1 == firstElem_2); } Ali
Apr 22 2012
prev sibling next sibling parent "Stephen Jones" <siwenjo gmail.com> writes:
Thanks for the replies. I am still uncertain about something. The 
documentation distinguishes between dynamic slices (int[5] a = 
new int[5]) which are managed by the runtime, and stack allocated 
arrays (int[5] b). The problem I have is this. I want to be 
loading vertex positions and tex-coords of data exported from 
Blender into openGL vertex buffers. Basically the float data 
needs to be extracted from a file and passed up to the graphic 
card's memory but to do so it needs to transit through the CPU 
memory. Ideally I want to:
     a) load the data from the file into an array built upon the 
stack and owned by a function
     b) generate the vbo id and send the data off to the graphics 
card
     c) pass the id back into a class held in managed memory
     d) quit the function thus releasing the array on the stack

My confusion is, if the syntax for both stack based and managed 
memory arrays is the same (&v[0] or &v.ptr) then both must be 
objects. I guess the difference is that stack based are of 
constant length, whereas slices are dynamic because they are 
managed by the runtime.
Apr 22 2012
prev sibling next sibling parent "jerro" <a a.com> writes:
On Sunday, 22 April 2012 at 22:17:11 UTC, Stephen Jones wrote:
 Thanks for the replies. I am still uncertain about something. 
 The documentation distinguishes between dynamic slices (int[5] 
 a = new int[5]) which are managed by the runtime, and stack 
 allocated arrays (int[5] b). The problem I have is this. I want 
 to be loading vertex positions and tex-coords of data exported 
 from Blender into openGL vertex buffers. Basically the float 
 data needs to be extracted from a file and passed up to the 
 graphic card's memory but to do so it needs to transit through 
 the CPU memory. Ideally I want to:
     a) load the data from the file into an array built upon the 
 stack and owned by a function
     b) generate the vbo id and send the data off to the 
 graphics card
     c) pass the id back into a class held in managed memory
     d) quit the function thus releasing the array on the stack

 My confusion is, if the syntax for both stack based and managed 
 memory arrays is the same (&v[0] or &v.ptr) then both must be 
 objects. I guess the difference is that stack based are of 
 constant length, whereas slices are dynamic because they are 
 managed by the runtime.

Dynamic arrays in D are represented with a struct containing a pointer to the start of data and a length. Static arrays are represented in the same way as they are in C - just the data is saved, the length is known at compile time and the pointer to data is computed from the stack frame pointer (or a pointer to struct if the static array is contained within a struct) and the offset which is also know at compile time, the same way the pointers to primitive types are computed. For example the following D program: import std.stdio; auto vp(T)(T* a){ return cast(void*) a; } struct S { int[8] a; int[8] b; int[] c; int[8] d; } void main() { S s; writeln( vp(&s.a) - vp(&s.a[0])); writeln(vp(&s.b) - vp(&s.a)); writeln(vp(&s.c) - vp(&s.b)); writeln(vp(&s.d) - vp(&s.c)); } and the following C program: #include <stdio.h> #define vp(a) (void*)(a) typedef struct { int* ptr; size_t length; } IntArray; typedef struct { int a[8]; int b[8]; IntArray c; int d[8]; } S; int main() { S s; printf("%d\n", vp(&s.a) - vp(&s.a[0])); printf("%d\n", vp(&s.b) - vp(&s.a)); printf("%d\n", vp(&s.c) - vp(&s.b)); printf("%d\n", vp(&s.d) - vp(&s.c)); return 0; } both print 0 32 32 16
Apr 22 2012
prev sibling next sibling parent "jerro" <a a.com> writes:
On Sunday, 22 April 2012 at 23:01:26 UTC, jerro wrote:
 On Sunday, 22 April 2012 at 22:17:11 UTC, Stephen Jones wrote:
 Thanks for the replies. I am still uncertain about something. 
 The documentation distinguishes between dynamic slices (int[5] 
 a = new int[5]) which are managed by the runtime, and stack 
 allocated arrays (int[5] b). The problem I have is this. I 
 want to be loading vertex positions and tex-coords of data 
 exported from Blender into openGL vertex buffers. Basically 
 the float data needs to be extracted from a file and passed up 
 to the graphic card's memory but to do so it needs to transit 
 through the CPU memory. Ideally I want to:
    a) load the data from the file into an array built upon the 
 stack and owned by a function
    b) generate the vbo id and send the data off to the 
 graphics card
    c) pass the id back into a class held in managed memory
    d) quit the function thus releasing the array on the stack

 My confusion is, if the syntax for both stack based and 
 managed memory arrays is the same (&v[0] or &v.ptr) then both 
 must be objects. I guess the difference is that stack based 
 are of constant length, whereas slices are dynamic because 
 they are managed by the runtime.

Dynamic arrays in D are represented with a struct containing a pointer to the start of data and a length. Static arrays are represented in the same way as they are in C - just the data is saved, the length is known at compile time and the pointer to data is computed from the stack frame pointer (or a pointer to struct if the static array is contained within a struct) and the offset which is also know at compile time, the same way the pointers to primitive types are computed. For example the following D program: import std.stdio; auto vp(T)(T* a){ return cast(void*) a; } struct S { int[8] a; int[8] b; int[] c; int[8] d; } void main() { S s; writeln( vp(&s.a) - vp(&s.a[0])); writeln(vp(&s.b) - vp(&s.a)); writeln(vp(&s.c) - vp(&s.b)); writeln(vp(&s.d) - vp(&s.c)); } and the following C program: #include <stdio.h> #define vp(a) (void*)(a) typedef struct { int* ptr; size_t length; } IntArray; typedef struct { int a[8]; int b[8]; IntArray c; int d[8]; } S; int main() { S s; printf("%d\n", vp(&s.a) - vp(&s.a[0])); printf("%d\n", vp(&s.b) - vp(&s.a)); printf("%d\n", vp(&s.c) - vp(&s.b)); printf("%d\n", vp(&s.d) - vp(&s.c)); return 0; } both print 0 32 32 16

Just to clarify, .ptr and .length aren't really fields, they are properties. Dynamic arrays are actually represented as structs containing a pointer and a length, but static arrays are not. The fact that they have .ptr and .length properties does not imply they are represented as structs with .ptr and .length fields.
Apr 22 2012
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 21 Apr 2012 18:25:44 -0400, Ali =C3=87ehreli <acehreli yahoo.com=
 wrote:

 In D, arrays are what they should have been in C :). A pointer and a  =

 size. Something the equivalent of the following (for the int type):

 struct int_Array
 {
      int * elements;
      size_t number_of_elements;
 }

Technically speaking, the number of elements comes first in the memory = layout. The fact that even seasoned D coders get it wrong (in fact, I h= ad = to look it up in druntime to be sure!) is a testament to how = well-encapsulated D slices actually are. -Steve
Apr 23 2012