going beyond your bounds

Derek Parnell derek at psych.ward
Thu May 21 02:30:34 PDT 2009


On Thu, 21 May 2009 04:51:16 -0400, MLT wrote:

> After a discussion on digitalmars.D I played with arrays a bit. Look at the following code:
> 		int[] a = [1,2,3,4,5,6,7,8,9] ;
> 		int[] b = a ;
> 		a ~= 10 ;
>                 b ~= 11 ;
> 		b[0] = 12 ;
> 		Stdout(b).newline ;
> 		Stdout(a).newline ;
> 
> The result is:
> [12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
> [12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
> 
> Which means that even though b was set only to a[0..10], after expanding b, also has direct access to element a[10]. But
> 		int[] a = [1,2,3,4,5,6,7,8,9] ;
> 		int[] b = a ;
> 		a ~= 10 ;
> 		b.length = b.length+1 ;
> 		b[0] = 11 ;
> 		Stdout(b).newline ;
> 		Stdout(a).newline ;
> 
> Gives 
> [11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
> [11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
> 
> Now b is expanded in length, but a side effect is that a[10] is set to 0 (i.e. initialized).
> 
> In the end, I think b can only see things that happen to a[10] after it expanded, but not before. It seems there is no way for the following to work:
> 		int[] a = [1,2,3,4,5,6,7,8,9] ;
> 		int[] b = a ;
> 		a ~= 10 ;
> 
> At this point, element a[10]=10 will never be visible to b. b can expand to it, but by doing that, a[10] will be overwritten.
> 
> Is this on purpose? It could also be useful to have b.length=b.length+1 which only initializes memory that has not been initialized before.

Yes it is on purpose.

Here is what is happening ...
The contents of the array variable is actually a 2-element struct {addr,
length}. When you assign one array to another, that struct is what is
copied, not the array data itself.

 int[] a = [1,2,3,4,5,6,7,8,9] ;
 // Now 'a' contains {adr, 9}

 int[] b = a ;
 // Now 'b' contains {adr, 9}

 a ~= 10 ;
 // Now 'a' contains {adr, 10} -- The address doesn't change
                               -- because the buffer allocation
                               -- still enough room for another element.

 b ~= 11 ;
 // Now 'b' contains {adr, 10} -- The address doesn't change
                               -- because the buffer allocation
                               -- still enough room for another element
                               -- And that new element overwrote the '10'
                               -- appended to 'a'.

 b[0] = 12 ;
 // The element at address 'adr' is modified. 
 // As both 'a' and 'b' point to the same area 
 // it appears that updating 'b' changes 'a'.


The safe way to copy the data of an array is to do ...
 int[] a = [1,2,3,4,5,6,7,8,9] ;
 int[] b = a.dup ; // COPY a's data to to b.
 a ~= 10 ;
 b ~= 11 ;
 b[0] = 12 ;

The result should now be:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]


So remember, assigning one array to another is just creating an alias to
the original array. You end up with two arrays pointing to the same data
buffer.

-- 
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell


More information about the Digitalmars-d-learn mailing list