Arrays that are passed by reference

J

Jack

If I don't specify "ref" in the argument list when passing an array to the
callee, I am passing the array (reference) by value. But this makes me
confused because it actually means a "reference" of a "reference"??As I pass
the array by value, the callee can change that array. However,when I use
ref, the callee and caller point to two different arrays. So could anyone
please explain the 2 different situations?
 
J

Jon Skeet [C# MVP]

If I don't specify "ref" in the argument list when passing an array to the
callee, I am passing the array (reference) by value.
Yes.

But this makes me
confused because it actually means a "reference" of a "reference"??As I pass
the array by value, the callee can change that array.

The callee can change the *contents* of the array.
However,when I use ref, the callee and caller point to two different arrays.

No they don't. Do you have some sample code which makes you think they
do?
So could anyone please explain the 2 different situations?

If you use ref, the callee can change which array the parameter refers
to, and that change will be made to the caller's variable too.

See http://pobox.com/~skeet/csharp/parameters.html for more
information.

Jon
 
A

Alberto Poblacion

Jack said:
If I don't specify "ref" in the argument list when passing an array to the
callee, I am passing the array (reference) by value. But this makes me
confused because it actually means a "reference" of a "reference"??As I
pass the array by value, the callee can change that array. However,when I
use ref, the callee and caller point to two different arrays. So could
anyone please explain the 2 different situations?

The array is always passed by reference. When you add the keyword "ref"
you are passing "a reference to the reference". Meaning that when you pass
the array without "ref", the procedure can change the contents of the array,
buy not the array to which the variable is pointing. The latter can be done
if you add "ref".
 
M

Marc Gravell

No; when you use "ref"", the callee and caller *still* point to the
same array. The difference is that in the latter case, if the callee
*re-assigns* the array (i.e. dataArg = new int[5]), then this is
reflected to the caller - i.e. the caller's reference is updated.
Normally this change would be local to the callee, and would not be
reflected to the caller.

For a full discussion, see Jon's pages:
http://www.yoda.arachsys.com/csharp/parameters.html

Marc
 
J

Jack

Jon Skeet said:
The callee can change the *contents* of the array.


No they don't. Do you have some sample code which makes you think they
do?

The book is called "C# for experienced programmers"
On page 127-130,


Using system;
....
public class ArrayReferenceTest : System.Windows.Forms.Form
{ ...
private void showOutputButton_Click(
object sender, System.EventArgs e)
{
int[] firstArray = { 1, 2, 3 };

int[] firstArrayCopy = firstArray;

outputLabel.Text = "Test passing firstArray reference by value";

outputLabel.Text = "\n\n Contents of firstArray " + "before calling
FirstDouble:\n\t";

for (int i = 0; i < firstArray.Length; i++)
outputLabel.Text += firstArray + " ";


FirstDouble (firstArray);

outputLabel.Text += "\n\nContents of firstArray after " + "calling
FirstDouble\n\t";


for (int i = 0; i < firstArray.Length; i++)
outputLabel.Text += firstArray + " ";

if ( firstArray == firstArrayCopy )
outputLabel.Text += "\n\nThe references refer to the same
array\n";
else
outputLabel.Text += "\n\nThe references refer to different
arrays\n";

int [] secondArray = { 1, 2, 3 };

int [] secondArrayCopy = secondArray;

outputLabel.Text += "\nTest passing secondArray " +
"reference by reference";

outputLabel.Text += "\nContents of secondArray " +
"before calling SecondDouble:\n\t";

for (int i = 0; i < secondArray.Length; i++ )
outputLabel.Text += secondArray + "\n";

SecondDouble (ref secondArray);

outputLabel.Text += "\n\nContents of secondArray " +
"after calling SecondDouble:\n\t";

for (int i = 0; i < secondArray.Length; i++)
outputLabel.Text += secondArray + " ";

if (secondArray == secondArrayCopy)
outputLabel.Text +=
"\n\nThe references refer to the same array\n";
else
outputLabel.Text +=
"\n\nThe references refer to different arrays\n";

}


void firstDouble (int [] array)
{
for (int i = 0; i < array.Length; i++)
array *= 2;

array = new int[] { 11, 12, 13 };
}

void SeondDouble (ref int[] array)
{
for (int i = 0; i < array.Length; i++)
array *= 2;

array = new int[] { 11, 12, 13 };
}
}
=================================
results:
Test passing firstArray reference by value

Contents of firstArray before calling FirstDouble
1 2 3

Contents of firstArray after calling FirstDouble
2 4 6

The references refer to the same array

Test passing secondArray reference by reference

Contents of secondArray before calling
SecondDouble:
1 2 3

Contents of secondArray after calling SecondDouble:
11 12 13

The references refer to different arrays

============================
Thanks
Jack
 
J

Jon Skeet [C# MVP]

The book is called "C# for experienced programmers"
On page 127-130,

<snip>

What this shows is that the callee can change the caller's variable's
value. When it says "The references refer to different arrays" is
means "the value of secondArray is different after calling
SecondDouble to the value it had before". It's *not* saying that the
value within the SecondDouble method is different to the value of
secondArray.

Jon
 
J

Jack

Starting to see some light on the other end after reading your+MS article,
haven't finished it though :)
Thanks
Jack


Jack said:
Jon Skeet said:
The callee can change the *contents* of the array.


No they don't. Do you have some sample code which makes you think they
do?

The book is called "C# for experienced programmers"
On page 127-130,


Using system;
...
public class ArrayReferenceTest : System.Windows.Forms.Form
{ ...
private void showOutputButton_Click(
object sender, System.EventArgs e)
{
int[] firstArray = { 1, 2, 3 };

int[] firstArrayCopy = firstArray;

outputLabel.Text = "Test passing firstArray reference by value";

outputLabel.Text = "\n\n Contents of firstArray " + "before
calling FirstDouble:\n\t";

for (int i = 0; i < firstArray.Length; i++)
outputLabel.Text += firstArray + " ";


FirstDouble (firstArray);

outputLabel.Text += "\n\nContents of firstArray after " + "calling
FirstDouble\n\t";


for (int i = 0; i < firstArray.Length; i++)
outputLabel.Text += firstArray + " ";

if ( firstArray == firstArrayCopy )
outputLabel.Text += "\n\nThe references refer to the same
array\n";
else
outputLabel.Text += "\n\nThe references refer to different
arrays\n";

int [] secondArray = { 1, 2, 3 };

int [] secondArrayCopy = secondArray;

outputLabel.Text += "\nTest passing secondArray " +
"reference by reference";

outputLabel.Text += "\nContents of secondArray " +
"before calling SecondDouble:\n\t";

for (int i = 0; i < secondArray.Length; i++ )
outputLabel.Text += secondArray + "\n";

SecondDouble (ref secondArray);

outputLabel.Text += "\n\nContents of secondArray " +
"after calling SecondDouble:\n\t";

for (int i = 0; i < secondArray.Length; i++)
outputLabel.Text += secondArray + " ";

if (secondArray == secondArrayCopy)
outputLabel.Text +=
"\n\nThe references refer to the same array\n";
else
outputLabel.Text +=
"\n\nThe references refer to different arrays\n";

}


void firstDouble (int [] array)
{
for (int i = 0; i < array.Length; i++)
array *= 2;

array = new int[] { 11, 12, 13 };
}

void SeondDouble (ref int[] array)
{
for (int i = 0; i < array.Length; i++)
array *= 2;

array = new int[] { 11, 12, 13 };
}
}
=================================
results:
Test passing firstArray reference by value

Contents of firstArray before calling FirstDouble
1 2 3

Contents of firstArray after calling FirstDouble
2 4 6

The references refer to the same array

Test passing secondArray reference by reference

Contents of secondArray before calling
SecondDouble:
1 2 3

Contents of secondArray after calling SecondDouble:
11 12 13

The references refer to different arrays

============================
Thanks
Jack





If you use ref, the callee can change which array the parameter refers
to, and that change will be made to the caller's variable too.

See http://pobox.com/~skeet/csharp/parameters.html for more
information.

Jon
 
M

Marc Gravell

Key code is this (where "array" may or may not be "ref")
for (int i = 0; i < array.Length; i++)
array *= 2;

array = new int[] { 11, 12, 13 };


When called without "ref", the values in the existing array are
doubled, and then a new unrelated array is created and assigned to
"array" - but the "array" variable and the "firstArray" variable are
unrelated; after the method ends, the caller just sees the original
array reference (whose contents have been doubled).

When called /with/ "ref", the values are doubled as before, and then a
new array is created and assigned (via some pointer dereferencing that
is a little complex) into the variable, but in this case "secondArray"
and "array" are one-and-the-same. The "ref" basically means "don't
create your own variable (on the stack) - use this one instead". So
the values are doubled, but are then discarded in preference for the
new array {11, 12, 13}. As such, at the end of the method the caller
can see the updated reference "secondArray".

The following is also slightly misleading:
int[] firstArray = { 1, 2, 3 };

int[] firstArrayCopy = firstArray;

This is a copy if the variable, /not/ the array (contents).

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top