0

Variable by val:

static void Main(string[] args)
{
    int i = 3;
    method1(i);
    Console.WriteLine(i);
    Console.ReadLine();
}
static void method1(int z)
{
    z *= 2;
}

The output is 3 because method1 didn't change the variable in Main.

Variable by ref:

static void Main(string[] args)
{
    int i = 3;
    method1(ref i);
    Console.WriteLine(i);
    Console.ReadLine();
}
static void method1(ref int z)
{
    z *= 2;
}

The output is 6 because method1 changed the variable in Main.

Array by val:

class Program
{
    static void Main(string[] args)
    {
        int[] i = { 13, 1, 5 };
        method1(i);
        Console.WriteLine(String.Join(",",i));
        Console.ReadLine();
    }
    static void method1(int[] z)
    {
        for(int m=0; m<z.Length;m++)
        {
            z[m] *= 2;
        }
    }
}

The output is 26, 2, 10.

Array by ref:

class Program
{
    static void Main(string[] args)
    {
        int[] i = { 13, 1, 5 };
        method1(ref i);
        Console.WriteLine(String.Join(",",i));
        Console.ReadLine();
    }
    static void method1(ref int[] z)
    {
        for(int m=0; m<z.Length;m++)
        {
            z[m] *= 2;
        }
    }
}

The output is again 26, 2, 10.

Conclusions: Variables can be passed either by value or by ref, in contrary to arrays that can be passed only by reference. Is it correct? If not - what is the difference between method1(ref int[] z) and method1(int[] z)? When are we expected to get different results?

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
Geri Reshef
  • 397
  • 1
  • 6
  • 17
  • 1
    Try doing something like `z = new int[10];` inside the method and you'll see – UnholySheep Mar 19 '17 at 10:39
  • 2
    There are reference types and value types. And then there is *passing by value* and *passing by reference*. Now multiply these to get 4 combinations. :) – vgru Mar 19 '17 at 10:42
  • What might be confusing you is that you are passing a *variable* in each of these 4 cases. The first variable is of type `int` (a value type), and the second one is of type `int[]` (a reference type). So in the first case you are passing the value of the `int` variable (a number), then a reference to the `int` variable (which allows you to change the original variable's value). In the third case you are again passing the value of the `int[]` variable (a reference to the array *somewhere in memory*) - this still doesn't enable you to change the **variable** `i`, only the contents of the array. – vgru Mar 19 '17 at 11:03
  • If you understand C pointers, you can compare this to having a local `int` variable and passing it to a function as 1) an `int` (int value), 2) a `int*` (pointer to a the `int` value located on the stack); **and in the second case** having a local `int*` variable and passing it to the function as 3) an `int*` (pointer to an `int` value on the heap), and 4) an `int**` (pointer to the local `int*` variable). – vgru Mar 19 '17 at 11:11

1 Answers1

4

When reference type object is passed by value, the reference to object is actually passed by value, so if you update the reference to a new object inside the method implementation the reference will start pointing to new memory address.

You can see the difference in results by modifying a little the method implementation, so that initialize the coming input array to a new instance like:

static void method1(int[] z)
{
   z = new int[3]; // new instance created and z has reference to it
                   // while calling side still refers to old memory location
                   // which is { 13, 1, 5 }
   for(int m=0; m<z.Length;m++)
   {
        z[m] *= 2;
    }
}

now when you call the pass by value method it will modify the z just locally for this method and the outer array would not be affected while if you pass it by reference then both array will get impacted with the changes.

What is happening is that we are setting the array z to reference to new memory location by creating a new array instance, so the reference in method gets updated to point to new memory location but the calling side reference is still pointing to the old array which was instantiated before calling the method.

When you are passing by reference the both the variable will get updated to point to the new memory location.

static void method1(ref int[] z)
{
   z = new int[3]; // new instance created and z has reference to it
                   // now calling side also refers to new memory location
                   // which is new int[3];
   for(int m=0; m<z.Length;m++)
   {
        z[m] *= 2;
    }
}
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • Thank you Ehsan Sajjad! I understand from your example that in the case of "by val" method1 will initialize a new array, and in the case of "by ref" it will reinitialize the existing array and all its elements will become zero. Is it correct? – Geri Reshef Mar 19 '17 at 10:46
  • "and in the case of "by ref" it will reinitialize the existing array" -- No. It will reassign the existing *variable*. The existing *array* will not be changed. You no longer have any way to refer to that existing array, but if you store a reference to it in another variable before calling `method1`, you'll see that it doesn't change. –  Mar 19 '17 at 10:52
  • no it will not, a new array is created and the old array reference is lost, but it is there in memory and will be soon collected by Garbage Collector – Ehsan Sajjad Mar 19 '17 at 10:57