www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - dynamic array of structs?

reply alexander.panek brainsware.org writes:
Hello,

I got a problem with an array of structs in a class: when I declare the array
inside the class as static, everything works fine. But as soon as I try to
handle that with a dynamical array it tells me "Error: ArrayBoundsError
<file(line)>". Is there no way to use dynamic arrays of structs? or did I just
misused that?

struct foo {
char[] x;
}

class bar {
private foo [] y;

this() { foo[0].x = "hello world"; } // <--- there i get the error
}

The only problem is, I didn`t find any simular examples in the documentation
(only structs and dynamical standard-type-arrays).

Hope you can help me.

Thanks, Alex
Nov 29 2004
next sibling parent reply Chris Sauls <Chris_member pathlink.com> writes:
In article <cofnsm$1510$1 digitaldaemon.com>, alexander.panek brainsware.org
says...
Hello,

I got a problem with an array of structs in a class: when I declare the array
inside the class as static, everything works fine. But as soon as I try to
handle that with a dynamical array it tells me "Error: ArrayBoundsError
<file(line)>". Is there no way to use dynamic arrays of structs? or did I just
misused that?

struct foo {
char[] x;
}

class bar {
private foo [] y;

this() { foo[0].x = "hello world"; } // <--- there i get the error
}

The problem here is a simple but common one. You are attempting to access the first value in a set with /zero/ items. Here are a couple of correct examples: this() { foo ~= "hello world"; } this() { foo.length = 1; foo[0] = "hello world"; } Even dynamic arrays have to be told their length before using them. I'm fond of the first method (concatenation) myself, but there are times when the second method is best. Experimentation will pay off here. -- Chris Sauls
Nov 29 2004
next sibling parent reply Stewart Gordon <Stewart_member pathlink.com> writes:
In article <cofq5q$18dv$1 digitaldaemon.com>, Chris Sauls says...
<snip>
 The problem here is a simple but common one.  You are attempting 
 to access the first value in a set with /zero/ items.  Here are a 
 couple of correct examples:
 
 this() {
 foo ~= "hello world";
 }

Read the OP's code again. foo is a data type. How can you append something to a data type? Stewart.
Nov 29 2004
parent reply Chris Sauls <Chris_member pathlink.com> writes:
In article <cofr30$19v7$1 digitaldaemon.com>, Stewart Gordon says...
In article <cofq5q$18dv$1 digitaldaemon.com>, Chris Sauls says...
<snip>
 The problem here is a simple but common one.  You are attempting 
 to access the first value in a set with /zero/ items.  Here are a 
 couple of correct examples:
 
 this() {
 foo ~= "hello world";
 }

Read the OP's code again. foo is a data type. How can you append something to a data type?

Miff... you can tell I've been missing sleep, neh? Change all the 'foo's to 'y's and all will be well. -- Chris Sauls
Nov 29 2004
parent "Ben Hinkle" <bhinkle mathworks.com> writes:
"Chris Sauls" <Chris_member pathlink.com> wrote in message
news:cofsei$1bvn$1 digitaldaemon.com...
 In article <cofr30$19v7$1 digitaldaemon.com>, Stewart Gordon says...
In article <cofq5q$18dv$1 digitaldaemon.com>, Chris Sauls says...
<snip>
 The problem here is a simple but common one.  You are attempting
 to access the first value in a set with /zero/ items.  Here are a
 couple of correct examples:

 this() {
 foo ~= "hello world";
 }

Read the OP's code again. foo is a data type. How can you append something to a data type?

Miff... you can tell I've been missing sleep, neh? Change all the 'foo's

 'y's and all will be well.

 -- Chris Sauls

the OP used foo[0].x as well so you aren't alone.
Nov 29 2004
prev sibling parent reply alexander.panek brainsware.org writes:
In article <cofq5q$18dv$1 digitaldaemon.com>, Chris Sauls says...
In article <cofnsm$1510$1 digitaldaemon.com>, alexander.panek brainsware.org
says...
Hello,

I got a problem with an array of structs in a class: when I declare the array
inside the class as static, everything works fine. But as soon as I try to
handle that with a dynamical array it tells me "Error: ArrayBoundsError
<file(line)>". Is there no way to use dynamic arrays of structs? or did I just
misused that?

struct foo {
char[] x;
}

class bar {
private foo [] y;

this() { foo[0].x = "hello world"; } // <--- there i get the error
}

The problem here is a simple but common one. You are attempting to access the first value in a set with /zero/ items. Here are a couple of correct examples: this() { foo ~= "hello world"; } this() { foo.length = 1; foo[0] = "hello world"; } Even dynamic arrays have to be told their length before using them. I'm fond of the first method (concatenation) myself, but there are times when the second method is best. Experimentation will pay off here. -- Chris Sauls

Well. I tried those and neither the '~='-operater helped, nor is the length-property available for an array of structs. Shall I use an array of pointers instead of dynamic arrays or just a pointer for that? Maybe that helps..gonna try. And before I forget: <code>
struct foo {
char[] x;
}

class bar {
private foo [] y;

this() { y[0].x = "hello world"; } // <--- there i get the error
}


better? :P Thanks, Alex
Nov 29 2004
next sibling parent reply Regan Heath <regan netwin.co.nz> writes:
On Mon, 29 Nov 2004 19:45:07 +0000 (UTC), <alexander.panek brainsware.org> 
wrote:
 In article <cofq5q$18dv$1 digitaldaemon.com>, Chris Sauls says...
 In article <cofnsm$1510$1 digitaldaemon.com>, 
 alexander.panek brainsware.org
 says...
 Hello,

 I got a problem with an array of structs in a class: when I declare 
 the array
 inside the class as static, everything works fine. But as soon as I 
 try to
 handle that with a dynamical array it tells me "Error: ArrayBoundsError
 <file(line)>". Is there no way to use dynamic arrays of structs? or 
 did I just
 misused that?

 struct foo {
 char[] x;
 }

 class bar {
 private foo [] y;

 this() { foo[0].x = "hello world"; } // <--- there i get the error
 }

The problem here is a simple but common one. You are attempting to access the first value in a set with /zero/ items. Here are a couple of correct examples: this() { foo ~= "hello world"; } this() { foo.length = 1; foo[0] = "hello world"; } Even dynamic arrays have to be told their length before using them. I'm fond of the first method (concatenation) myself, but there are times when the second method is best. Experimentation will pay off here. -- Chris Sauls

Well. I tried those and neither the '~='-operater helped, nor is the length-property available for an array of structs. Shall I use an array of pointers instead of dynamic arrays or just a pointer for that? Maybe that helps..gonna try. And before I forget: <code>
 struct foo {
 char[] x;
 }

 class bar {
 private foo [] y;

 this() { y[0].x = "hello world"; } // <--- there i get the error
 }


better? :P

Both 'x' and 'y' are dynamic arrays. Both require you to explicitly extend the length of them, or, use the append operator '~'. Example: import std.stdio; struct foo { char[] x; } version(EXTEND) { class bar { private foo[] y; this() { foo f; writef("EXTEND\n"); f.x = "hello world"; y ~= f; } } } else { class bar { private foo[] y; this() { foo f; writef("APPEND\n"); f.x = "hello world"; y.length = y.length + 1; y[y.length-1] = f; } } } void main() { bar b = new bar(); writef(b.y[0].x,"\n"); } compile with: "dmd dynamic.d" for the append version "dmd dynamic.d -version=EXTEND" for the extend version Also note that: y[y.length-1] = f; copies the 'f' foo structure into the array, which isn't a problem unless the struct is large in which case it is slower than using a class (which is a reference type thus all you copy is the reference to the class, not the actual class itself). If you want speed and to use a struct then consider a struct pointer i.e. struct foo { char[] x; } class bar { private foo*[] y; this() { foo *f = new foo(); f.x = "hello world"; y ~= f; } } Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Nov 29 2004
parent alexander.panek brainsware.org writes:
In article <opsh8wwchn5a2sq9 digitalmars.com>, Regan Heath says...
On Mon, 29 Nov 2004 19:45:07 +0000 (UTC), <alexander.panek brainsware.org> 
wrote:
 In article <cofq5q$18dv$1 digitaldaemon.com>, Chris Sauls says...
 In article <cofnsm$1510$1 digitaldaemon.com>, 
 alexander.panek brainsware.org
 says...
 Hello,

 I got a problem with an array of structs in a class: when I declare 
 the array
 inside the class as static, everything works fine. But as soon as I 
 try to
 handle that with a dynamical array it tells me "Error: ArrayBoundsError
 <file(line)>". Is there no way to use dynamic arrays of structs? or 
 did I just
 misused that?

 struct foo {
 char[] x;
 }

 class bar {
 private foo [] y;

 this() { foo[0].x = "hello world"; } // <--- there i get the error
 }

The problem here is a simple but common one. You are attempting to access the first value in a set with /zero/ items. Here are a couple of correct examples: this() { foo ~= "hello world"; } this() { foo.length = 1; foo[0] = "hello world"; } Even dynamic arrays have to be told their length before using them. I'm fond of the first method (concatenation) myself, but there are times when the second method is best. Experimentation will pay off here. -- Chris Sauls

Well. I tried those and neither the '~='-operater helped, nor is the length-property available for an array of structs. Shall I use an array of pointers instead of dynamic arrays or just a pointer for that? Maybe that helps..gonna try. And before I forget: <code>
 struct foo {
 char[] x;
 }

 class bar {
 private foo [] y;

 this() { y[0].x = "hello world"; } // <--- there i get the error
 }


better? :P

Both 'x' and 'y' are dynamic arrays. Both require you to explicitly extend the length of them, or, use the append operator '~'. Example: import std.stdio; struct foo { char[] x; } version(EXTEND) { class bar { private foo[] y; this() { foo f; writef("EXTEND\n"); f.x = "hello world"; y ~= f; } } } else { class bar { private foo[] y; this() { foo f; writef("APPEND\n"); f.x = "hello world"; y.length = y.length + 1; y[y.length-1] = f; } } } void main() { bar b = new bar(); writef(b.y[0].x,"\n"); } compile with: "dmd dynamic.d" for the append version "dmd dynamic.d -version=EXTEND" for the extend version Also note that: y[y.length-1] = f; copies the 'f' foo structure into the array, which isn't a problem unless the struct is large in which case it is slower than using a class (which is a reference type thus all you copy is the reference to the class, not the actual class itself). If you want speed and to use a struct then consider a struct pointer i.e. struct foo { char[] x; } class bar { private foo*[] y; this() { foo *f = new foo(); f.x = "hello world"; y ~= f; } } Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/

I thank you very much! First really helpful message! Works now! :) Alex
Nov 29 2004
prev sibling parent Dave <Dave_member pathlink.com> writes:
In article <cofu83$1ee2$1 digitaldaemon.com>, alexander.panek brainsware.org
says...
Well. I tried those and neither the '~='-operater helped, nor is the
length-property available for an array of structs. Shall I use an array of
pointers instead of dynamic arrays or just a pointer for that? Maybe that
helps..gonna try.

Thanks, Alex

Both the concat. operator and length prop. will work Ok like so:
import std.stream;
import std.string;

struct foo {
    char[] x;
}

class bar {
    private foo[] y;
    this()
    {
        y ~= new foo[1];
        y[0].x = "hello world";
    }
    this(int x)
    {
        y.length = x;
        foreach(int idx, inout foo f; y) { 
            f.x = "hello world (" ~ std.string.toString(idx) ~ ")";
        }
    }
}

void main()
{
    {
        bar B = new bar;
        stdout.writefln(B.y[0].x);
    }
    {
        bar B = new bar(100);
        foreach(foo f; B.y) {
            stdout.writefln(f.x);
        }
    }
}

- Dave
Nov 29 2004
prev sibling next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
alexander.panek brainsware.org wrote:
 Hello,
 
 I got a problem with an array of structs in a class: when I declare the array
 inside the class as static, everything works fine. But as soon as I try to
 handle that with a dynamical array it tells me "Error: ArrayBoundsError
 <file(line)>". Is there no way to use dynamic arrays of structs? or did I just
 misused that?
 
 struct foo {
 char[] x;
 }
 
 class bar {
 private foo [] y;
 
 this() { foo[0].x = "hello world"; } // <--- there i get the error
 }
 
 The only problem is, I didn`t find any simular examples in the documentation
 (only structs and dynamical standard-type-arrays).

The issue has nothing to do with structs, it turns out. The same problem would be true with classes. First, you have a syntax error. In the last line, you attempt to access foo[0] but foo is a type. So this is obviously wrong. You can't use a type like it was an array variable. So I'm going to assume that you meant to do this: this() { y[0].x = "hello world"; } The problem is, indeed, that you are accessing an invalid element of an array. In this code, the array 'y' has 0 elements. So you can't access any element of it until you put some elements in it. Probably the easiest way to do it is: this() { y.length = 1; y[0].x = "hello world"; } Otherwise, you'll get an ArrayBoundsError the moment that you try to access y[0] Now, why does it work when you make x static? That's because, when you have a static variable, it can be accessed through any instance of the struct. The instance doesn't have to be valid; the compiler only needs to know the type, and the rest of it is removed at compile time. So, consider this code: struct fred { static char[] x; } struct wilma { private fred[] y; this() { y[0].x = "hello world"; } } The last line of that code is totally the same as this code: this() { fred.x = "hello world"; } So, since the compiler doesn't actually attempt to access y[0] in the static case, you don't get the ArrayBoundsError. This is very similar to the code that is often used to find the offset of a member variable in a struct: struct X { int a; int b; } int offset_of_b = &((cast(X*)0).b); In the above, you have a pointer variable which points to 0 (i.e. null). It's obviously invalid to try to access the 'b' member of that struct. But, since we only take the *address* of 'b' and we don't actually try to read it, we are ok. The compiler actually should simplify it down to a constant value, so the line becomes something like: int offset_of_b = 4; (Of course, I think D provides a property which allows us to get this more easily...but I can't remember exactly what it is.)
Nov 29 2004
parent reply alexander.panek brainsware.org writes:
In article <cog3t3$1mhg$1 digitaldaemon.com>, Russ Lewis says...
alexander.panek brainsware.org wrote:
 Hello,
 
 I got a problem with an array of structs in a class: when I declare the array
 inside the class as static, everything works fine. But as soon as I try to
 handle that with a dynamical array it tells me "Error: ArrayBoundsError
 <file(line)>". Is there no way to use dynamic arrays of structs? or did I just
 misused that?
 
 struct foo {
 char[] x;
 }
 
 class bar {
 private foo [] y;
 
 this() { foo[0].x = "hello world"; } // <--- there i get the error
 }
 
 The only problem is, I didn`t find any simular examples in the documentation
 (only structs and dynamical standard-type-arrays).

The issue has nothing to do with structs, it turns out. The same problem would be true with classes. First, you have a syntax error. In the last line, you attempt to access foo[0] but foo is a type. So this is obviously wrong. You can't use a type like it was an array variable. So I'm going to assume that you meant to do this: this() { y[0].x = "hello world"; } The problem is, indeed, that you are accessing an invalid element of an array. In this code, the array 'y' has 0 elements. So you can't access any element of it until you put some elements in it. Probably the easiest way to do it is: this() { y.length = 1; y[0].x = "hello world"; } Otherwise, you'll get an ArrayBoundsError the moment that you try to access y[0] Now, why does it work when you make x static? That's because, when you have a static variable, it can be accessed through any instance of the struct. The instance doesn't have to be valid; the compiler only needs to know the type, and the rest of it is removed at compile time. So, consider this code: struct fred { static char[] x; } struct wilma { private fred[] y; this() { y[0].x = "hello world"; } } The last line of that code is totally the same as this code: this() { fred.x = "hello world"; } So, since the compiler doesn't actually attempt to access y[0] in the static case, you don't get the ArrayBoundsError. This is very similar to the code that is often used to find the offset of a member variable in a struct: struct X { int a; int b; } int offset_of_b = &((cast(X*)0).b); In the above, you have a pointer variable which points to 0 (i.e. null). It's obviously invalid to try to access the 'b' member of that struct. But, since we only take the *address* of 'b' and we don't actually try to read it, we are ok. The compiler actually should simplify it down to a constant value, so the line becomes something like: int offset_of_b = 4; (Of course, I think D provides a property which allows us to get this more easily...but I can't remember exactly what it is.)

First of all: foo[0]... was a typing error. I meant y[0]. The problem will be, that I don`t only have to access one array-member. I want to save an XML-Attribute into this struct (name, value) - so I have to fill this dynamically (used for parsing and such things). I don`t remember a better way to do something like that, as to use a struct to combine the data and not just writing it into the class as seperate variables. Alex
Nov 29 2004
parent Sjoerd van Leent <svanleent wanadoo.nl> writes:
alexander.panek brainsware.org wrote:

 
 First of all: foo[0]... was a typing error. I meant y[0].
 
 The problem will be, that I don`t only have to access one array-member. I want
 to save an XML-Attribute into this struct (name, value) - so I have to fill
this
 dynamically (used for parsing and such things).
 
 I don`t remember a better way to do something like that, as to use a struct to
 combine the data and not just writing it into the class as seperate variables.
 
 Alex
 
 

There is. Use a associative array (or map). They are always fully dynamic. Example: struct SomeStruct { char[] s; } int main(char[][] args) { SomeStruct[int] structs; SomeStruct s1; s1.s = "String 1"; structs[0] = s1; SomeStruct s2; s2.s = "String 2"; structs[1] = s2; return 0; } Note that using 0 and 1 again causes it to be overwritten. Regards, Sjoerd
Nov 29 2004
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 29 Nov 2004 17:56:38 +0000 (UTC), alexander.panek brainsware.org
wrote:

 struct foo {
 char[] x;
 }
 
 class bar {
 private foo [] y;
 
 this() { foo[0].x = "hello world"; } // <--- there i get the error
 }

This worked for me ... <code> import std.stdio; struct foo { char[] x; } class bar { private foo [] y; this() { y.length = 1; y[0].x ~= "hello world"; } } void main() { bar B = new bar; writefln("%s\n", B.y[0].x); } </code> -- Derek Melbourne, Australia 30/11/2004 9:11:42 AM
Nov 29 2004
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Derek Parnell wrote:
 class bar {
     private foo [] y;
 
     this() 
     {
         y.length = 1;
         
         y[0].x ~= "hello world"; 
     }
 }

Wouldn't y[0].x = "hello world"; work just as well, since x is empty?
Nov 29 2004
parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 29 Nov 2004 17:26:35 -0700, Russ Lewis wrote:

 Derek Parnell wrote:
 class bar {
     private foo [] y;
 
     this() 
     {
         y.length = 1;
         
         y[0].x ~= "hello world"; 
     }
 }

Wouldn't y[0].x = "hello world"; work just as well, since x is empty?

Yep, sure would. I guess I was just being a bit paranoid wanting to ensure that a copy of the string was assigned rather than just a reference. But a simple '=' does that in this context anyway. -- Derek Melbourne, Australia 30/11/2004 2:13:15 PM
Nov 29 2004
parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Derek Parnell wrote:
 On Mon, 29 Nov 2004 17:26:35 -0700, Russ Lewis wrote:
Wouldn't
	y[0].x = "hello world";
work just as well, since x is empty?

Yep, sure would. I guess I was just being a bit paranoid wanting to ensure that a copy of the string was assigned rather than just a reference. But a simple '=' does that in this context anyway.

Well, if you really want to make sure that you are assiging a copy, then y[0].x = "hello world".dup; should work.
Nov 30 2004
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
alexander.panek brainsware.org wrote:
<snip>
[ArrayBoundsError]
 struct foo {
 char[] x;
 }
 
 class bar {
 private foo [] y;
 
 this() { foo[0].x = "hello world"; } // <--- there i get the error
 }

Unless I'm missing something, it can only be a bug that this compiles. What does DMD think it means? (I haven't tested it in 0.107 yet.) Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Nov 30 2004
parent "Simon Buchan" <currently no.where> writes:
On Tue, 30 Nov 2004 10:28:39 +0000, Stewart Gordon <smjg_1998 yahoo.com>  
wrote:

 alexander.panek brainsware.org wrote:
 <snip>
 [ArrayBoundsError]
 struct foo {
 char[] x;
 }
  class bar {
 private foo [] y;
  this() { foo[0].x = "hello world"; } // <--- there i get the error
 }

Unless I'm missing something, it can only be a bug that this compiles. What does DMD think it means? (I haven't tested it in 0.107 yet.) Stewart.

1.07 gives: bugtest.d(8): no [] operator overload for type foo -- "Unhappy Microsoft customers have a funny way of becoming Linux, Salesforce.com and Oracle customers." - www.microsoft-watch.com: "The Year in Review: Microsoft Opens Up" "Clearly, if I were one of that Predator hunting team, I would file a complaint with my local member asking why such an unsafe environment should be allowed to continue, tradition or not." - http://www.sydneyanglicans.net/culture/watching/alien_vs_predator/
Nov 30 2004