Arrays, copied or referenced?

Kirk McDonald kirklin.mcdonald at gmail.com
Sun Aug 5 15:34:55 PDT 2007


Audun Wilhelmsen wrote:
> Hey..
> 
> Take this code: 
> --------------------------
> import std.stdio;
> 
> int[] arrayTest(int[] a) {
> 	a.length = 5;
> 	a[4] = 42;
> 	return a;
> }
> 
> int main(char[][] args) {
> 	int[10] foobar;
> 	foobar[4] = 2;
> 	arrayTest(foobar);
> 	writefln("%d", foobar[4]);
>         return 0;
> }
> --------------------------
> It prints out "42".
> Now replace the line "a.length = 20", and it prints out "2".
> 
> Is that the way it's supposed to behave?
> 
> Audun Wilhelmsen
> NTNU, Norway

I've set the Followup-To to digitalmars.D.learn.

This is perhaps a tricky subject. The answer is yes, that is the correct 
behavior.

Let me copy your function again:

int[] arrayTest(int[] a) {
	a.length = 5;
	a[4] = 42;
	return a;
}

Dynamic arrays in D are a struct that looks something like this:

struct dyn_array {
	void* ptr;
	size_t length;
}

When you pass an array to arrayTest, it passes this struct by value. 
When you say:

a.length = 5;

There is some logic that it does behind the scenes. If the new length is 
shorter than the old length, it simply changes the length attribute of 
the struct, and the pointer refers to the same chunk of memory that it 
did before. If the new length is longer than the chunk of memory to 
which ptr points (which in this example is a static array in main, so 
this is always true if you make the length longer), it will allocate a 
new array on the heap, and copy the array contents into it.

Thus, when you say 'a.length = 20', you're suddenly referring to a 
different chunk of memory. This allocation is not always guaranteed to 
happen, which is why I said this is a tricky subject.

To get actual reference semantics, you should use something like this:

void arrayTest(ref int[] a) {
	a.length = 20;
	a[4] = 42;
}

void main() {
	int[] foobar = new int[](10);
	foobar[4] = 2;
	arrayTest(foobar);
	writefln("%d", foobar[4]);
}

Note the 'ref' in arrayTest's parameter. Also note that it's passing an 
int[] and not an int[10] to arrayTest: You can't assign a dynamic array 
to a static array.

However, if you're just passing the contents of the array to a function, 
and not modifying the array itself, passing a regular int[] will get you 
all of the reference semantics you need.

-- 
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org



More information about the Digitalmars-d mailing list