An array is a reference
In the theme on variables, assignment copied the value: after b = a and a = 7, b still held the old number. With arrays the same assignment behaves differently:
int[] a = [1, 2, 3];
int[] b = a;
b[0] = 10;
Console.WriteLine(a[0]); // 10
Console.WriteLine(b[0]); // 10Let's go through it line by line:
int[] a = [1, 2, 3];creates an array and gives it the namea.int[] b = a;does not create a second array. Now the same array has two names:aandb.b[0] = 10;changes the first element of this one array.- That is why
a[0]is10too:aandbshow the same thing.
Back to the lockers. The row of lockers stands in the changing room, and in your hand is a key to that row. An array variable is the key, not the lockers themselves. The line int[] b = a; cuts a copy of the key: there are now two keys, but still one row. Open a locker with the first key and put something in: with the second key you find it in the same place.
The variable holds a reference
While a program runs, all its values, from numbers to arrays, are kept in the computer's memory: that is the changing room where the lockers stand. The array itself sits in memory apart from the variable. The variable holds a reference: a value the program uses to find the array in memory. That is the key to the row of lockers.
Types whose variables hold a reference are called reference types, and arrays are a reference type. int, double and bool, on the other hand, are value types: their variable holds the value itself.
Assignment copies what the variable holds. For an int that is the number itself, for an array it is the reference. So b = a copies the key, not the lockers.
In the widget, an array variable shows an arrow instead of a value: → [1, 2, 3] means "leads to an array with these elements". Press "Next step" and read the caption: it says whether the names share one array.
1int[] a = [1, 2, 3];2int[] b = a;3b[0] = 10;4Console.WriteLine(a[0]);5ZeroLast(a);6Console.WriteLine(b[2]);7b = [7, 8, 9];8Console.WriteLine(a[0]);9Console.WriteLine(b[0]);10 11void ZeroLast(int[] nums)12{13 nums[nums.Length - 1] = 0;14}
An array is created, and a gets a reference to it.
While two variables hold one reference, a write through either name shows through the other. A method that receives an array gets one more name for the same array. The names part ways only when one of them is assigned a different array.
The key can be changed
Here the key picture is not quite right. A real key fits one lock forever. A reference variable, though, can be assigned a reference to another array, and from then on it leads there. The new array can have any length: the type int[] sets no length; only the array itself has one.
After b = [7, 8, 9], b holds a key to a new row, while the key in a still opens the old one. The old array does not change: assigning a variable does not touch the elements.
An array as a method parameter
A method parameter gets a copy of the argument, so a method cannot change the variable passed to it. For an array the rule is the same, only what gets copied is the reference:
int[] prices = [100, 250, 80];
Discount(prices);
Console.WriteLine(prices[1]); // 225
Replace(prices);
Console.WriteLine(prices[1]); // 225
void Discount(int[] nums)
{
nums[1] = nums[1] - 25;
}
void Replace(int[] nums)
{
nums = [0, 0, 0];
}Let's go through both calls:
Discount(prices)copies the reference inpricesinto the parameternums: the method has its own key to the same array.nums[1] = nums[1] - 25changes an element of the shared array, so after the callprices[1]is225.Replace(prices)also gets a copy of the reference, but puts a reference to a new array intonums. Only the copy of the key changes.pricesstill leads to the old array, and225is printed again.
Interviewers like to ask this: can a method change an array passed to it? The answer has two parts:
- its elements, yes: the method gets a copy of the reference and changes the same array;
- the caller's variable itself, no: assigning to the parameter changes only the copy of the reference.
With ref int[] nums, the method would get the variable prices itself and could put a reference to a new array into it. Without ref, an array, like an int, is passed by value, not by reference: what gets copied is the reference the variable holds.
A real copy
Sometimes you need a second row of lockers with the same things in it, to change the copy and leave the original alone. For that you create a new array of the same length and copy the elements into it with Array.Copy:
int[] original = [1, 2, 3];
int[] copy = new int[original.Length];
Array.Copy(original, copy, original.Length);
copy[0] = 10;
Console.WriteLine(original[0]); // 1
Console.WriteLine(copy[0]); // 10Array.Copy(original, copy, original.Length) copies from original into copy as many elements as the third argument says. After that the arrays share no elements, and a write to copy leaves original alone.
Common mistake
Two arrays with the same elements were compared with ==:
int[] a = [1, 2, 3];
int[] b = [1, 2, 3];
bool same = a == b; // ✗
Console.WriteLine(same); // FalseThe program compiles and prints False, even though the elements are the same. For arrays, == compares references: it checks whether this is one array. Here there are two arrays, like two rows of lockers holding the same things. To compare the contents, you check the lengths and then the elements one by one in a loop.
Key points
- An array variable holds a reference to the array, not the elements themselves: arrays are a reference type.
int[] b = a;copies the reference: the array gets two names, and a write throughbshows througha.- A method that receives an array can change its elements, but assigning to the parameter does not change the caller's variable.
- A real copy takes a new array and
Array.Copy;==on arrays checks whether they are one array.