C# Pass By Value

Pass by Value vs Reference

Pass by value


When we pass call a function, we sometimes pass in some values for the function to use. Typically, it would look like this

(parameters)

or

void swapValues(int x, int y)

When we pass a value to the function swapValue(), we are passing it by value.

What this means is that, a new memory region is allocated from the stack for the new parameters x and y, and the value of that memory region is set to the value that was passed to it.

I’ll write a post on what happens in the memory region when a function is called in the future (dealing with functions stack frame allocation etc). But for now, when we call a function, it is allocated a function stack frame, with all its variables and paramters contained within the frame.

Let’s look at the following code block

public static void Main()
{
int x = 10;
int y = 20;

swapValues(10, 20);
}

void swapValues(int x, int y)
{
int temp;

temp = x;
x = y;
y = temp;
}

When Main() calls swapValues(), a new stack frame is allocated just for swapValues() to store all its local variables, and parameters passed into it. The stack frame will be the new memory region for the two paramters x and y, and assigns them to the values that was passed to them, which are 10 and 20.

Because it’s a new memory region, whatever changes that are done in the function swapValues() will only affect the newly allocated memory regions of x and y in the stack frame of swapValues().

That is to say, the values of x and y in the Main function stack frame will be left untouched!

This kind of defeats the purpose of the function…

So how do we fix it?

Pass by Reference


Let’s tweak the code above slightly to make it pass by reference

public static void Main()
{
int x = 10;
int y = 20;

swapValues(10, 20);
}

void swapValues(ref int x, ref int y)
{
int temp;

temp = x;
x = y;
y = temp;
}

The only difference is adding the keyword ref in front of the function parameters, which tell the function to reference to the objects passed in. This means that whatever work that is done in swapValues() will work directly on the values in Main()

The difference between passing by value and passing by reference is shown below

  • Passing by value: Allocates memory space on the stack frame and assigns it the value of the object that were passed into the function
  • Passing by reference: Does not allocate memory space on the stack frame, uses the object that was passed in directly

In this case, whatever changes done to x and y in the function swapValues() will directly modify the values inside the stack frame of Main()!

Reference Objects


Modifying the reference object part 1

Now heres the tricky part. Some objects are reference objects, which is to say they are pointers to begin with. An example would be a string in C, or an array object.

public static void Main()
{
int[] myArrayMain = new int[] {1, 2, 3, 4, 5};

editArray(myArrayMain);
}

void editArray(int[] myArrayParam)
{
myArrayParam[0] = 7;
}

The above code will changes myArrayMain to {0, 2, 3, 4, 5}

When we call the function editArray(), we create a new stack frame for editArray() to hold its local variables and paramters. Because myArrayParam is a reference object, we create a pointer on the stack frame to hold any value that is passed into myArrayParam.

We are passing in myArrayMain, which is a reference object. That means, the value of myArrayMain is an address, which points to the first element in the array.

When we pass myArrayMain to myArrayParam, we are assigning myArrayParam to the value of the myArrayMain, which is an address that points to the first element of myArrayMain!

Memory pointer layout:

myArrayParam –> myArrayMain –> memory of first element in myArrayMain (1)

So any changes made to myArrayParam in editArray() will be propagated to the myArrayMain

Modifying the reference object part 2

Now what happens when we change editArray() to create a new array? Will myArrayMain be overwritten?

public static void Main()
{
int[] myArrayMain = new int[] {1, 2, 3, 4, 5};

editArray(myArrayMain);
}

void editArray(int[] myArrayParam)
{
myArrayParam[0] = new int[] {6, 7, 8, 9, 10};
}

Nope. myArrayMain will still remain as {1, 2, 3, 4, 5}

When we call myArrayParam[0] = new int[] {6, 7, 8, 9, 10};, we are repointing myArrayParam to something else. This breaks the memory pointer layout above

myArrayParam --> myArrayMain --> memory of first element in myArrayMain (1)

becomes

myArrayParam --> memory of first element in myArrayParam (6)

myArrayMain --> memory of first element in myArrayMain (1)

Modifying the reference object part 3

Lets look at the final attempt. This time, we call ref on the array that is passed in

public static void Main()
{
int[] myArrayMain = new int[] {1, 2, 3, 4, 5};

editArray(myArrayMain);
}

void editArray(ref int[] myArrayParam)
{
myArrayParam[0] = new int[] {6, 7, 8, 9, 10};
}

Remember that when we call ref, in the stack frame of editArray(), no new memory is allocted, and the original myArrayMain is used.

The memory pointer layout is now

myArrayParam --> memory of first element in myArrayMain (1)

myArrayMain --> memory of first element in myArrayMain (1)

Both myArrayParam and myArrayMain now point to the first element in myArrayMain

So when the code block is ran, myArrayMain will change to {6, 7, 8, 9, 10}!

Conclusion


Phew! That was a long and confusing read, so here’s a TLDR:

  • C# passes by value
  • When a function is called, a stack frame is allocated for local and parameter variables
  • The parameter variables are assigned to the value that was passed in
  • No memory in the stack frame is allocated for parameters that are prefixed with ref, but are accessed directly from the caller function
  • Arrays are reference objects
  • The values they hold are the memory space of the first element in the array

Thanks for reading!!

Further reading: http://www.yoda.arachsys.com/csharp/parameters.html Excellent page!!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s