C# Pass-by-reference – Concept and example

March 15, 2015 at 5:20 pm Leave a comment

670px-Pass-a-Soccer-Ball-Step-3-Version-2One of the concepts that many of my beginning programming students find difficult to wrap their heads around is the different ways that arguments can be passed when a method is called.  The two mechanisms for passing an argument to a method are pass-by-value and pass-by-reference.

(No, this post isn’t about soccer, I just wanted to get you thinking about passing.)

Advice to new programmers: Skip this paragraph. But the rest of this post is for you!
Before launching into our discussion, I need to clarify that we’re only talking about what happens when we pass value types to method parameters. Value types are the types enum and struct. The numeric types and bool type that are built into C# are all actually structs and so they are all value types. Interestingly, strings are not value types, they are reference types, but that’s a topic for another post!

I should make another clarification too. When I talk about the code that calls a method, I refer to the variables passed to the method as arguments, but when I talk about the code that defines a method, I call the variables inside the parenthesis parameters.

Pass by Value
Let’s take a look at a “normal” C# method definition:

     int Sum(int num1, int num2)    // this method returns the sum of num1 and num2
     {
          return num1 + num2;
     }

The parameters num1 and num2 use the default mechanism for passing an argument to a method, pass-by-value. This means that the value contained in the argument is what is passed to the method. In other words, the argument’s contents are copied into the method’s parameter. For example, we can call the method above like this:

     int a = 4, b = 8, result = 0;
     result = Sum(a, b);

In the example above there are four variables involved: a and b, and num1 and num2. When the method is called, the values contained in a and b are copied to num1 and num2.

In order to see the implications of this, consider another method:

     int determineHighScore(int highScore, int newScore)
     {
          if (newScore > highScore)
               highScore = newScore;

          return highScore;
     }

Here’s the code to call the method:

int leadingScore= 0;
int score = 0;

// Imagine some game code that sets a new value for the score
score = 8;
leadingScore = determineHighScore(leadingScore, score);

// imagine some more game code that sets another value in score
score = 6;
leadingScore = determineHighScore(leadingScore, score)

// This will display the new leadingScore of 8
MessageBox.Show("The high score is: " + leadingScore.ToString());

In the example above, the values contained in leadingScore and score are copied into highScore and newScore when the determineHighScore method is called.  Since the variable highScore (inside the method) contains a copy of leadingScore, nothing happens to the value in leadingScore when we change the value in highScore. That’s why we have to return the value contained by highScore and assign it to leadingScore.

Pass by Reference
Now consider another version of the method determineHighScore:

     void determineHighScore(ref int highScore, int score)
     {
          if (score > highScore)
               highScore = score;
     }

Now we’ll call the method a couple times, sort of like we did before, except this is a void method and it doesn’t return a new value for leadingScore.

int leadingScore= 0;
int score = 0;

// Imagine some game code that sets a new value for the score
score = 8;
determineHighScore(leadingScore, score);

// imagine some more game code that sets another value in score
score = 6;
determineHighScore(leadingScore, score);

// This will display the new leadingScore of 8
MessageBox.Show("The high score is: " + leadingScore.ToString());

In this example we used a reference parameter. We did this by employing the keyword ref in both the method definition and the method call. Because we did this, the mechanism by which the argument was passed to the method was pass-by-reference. What this means is that instead of copying the value in leadingScore and passing the copy to highScore, a reference to leadingScore is passed. This means that it is as if the variable itself was passed and now highScore is just another name for leadingScore. Now anything we do to highScore is also done to leadingScore. This is why we don’t have to return highScore and assign it’s value to leadingScore.

What happens in memory?
To understand pass-by-reference better, we need to think about what is happening in memory. First, it is important to remember that a variable is a named memory location. Each variable occupies some number of bytes of memory at some particular memory address. We don’t have to worry about how many bytes or what the memory address is- that is all taken care of for us by C#. We just work with variable names.

With that in mind, lets look first at what happens with pass-by-value. When a variable is passed to a method using the default mechanism of pass-by-value, the contents of that variable’s memory location are copied into the memory location used by the variable defined by the method parameter. There are two memory locations involved and information is copied from one location to the other.

With pass-by-reference, we still have a memory location that is represented by the variable that is passed to the method. But, what is passed is the address of the memory location- not a copy of the information it contains. The variable defined by the method parameter becomes another name for that same memory location. Now there are two variable names that represent the same memory location. So, any change we make to the variable inside the method is also a change to variable passed to the method- since they represent the same memory location.

Thinking back to our determineHighScore example, there were four variables involved and four memory locations in the pass-by-value version: leadingScore, score, highScore, and newScore. But in the pass-by-reference version, while we had the same four variables, there were just two memory locations involved since leadingScore and highScore were both names for the same memory location as were score and newScore.

An analogy
An illustration might be helpful. For pass-by-value, imagine that you have a document on your computer that you want to let a friend edit. One way to do it would be to e-mail the friend a copy of the file. Clearly any changes the friend makes won’t affect your original, unless your friend returns the e-mail with the modified copy attached and then you replace the original with it.

Now, for pass-by-reference imagine that your original version is in dropbox (or on G drive, OneDrive, iCloud, etc.) You send your friend a link to the document. Now your friend can directly edit the original.

That’s it! Feel free to post questions and comments.

Entry filed under: C Sharp, Programming. Tags: , , .

Happy Pi Day! Why my next PC will be a Mac!

Leave a comment

Trackback this post  |  Subscribe to the comments via RSS Feed


Bird’s Bits

Computers, software & the Internet

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 41 other subscribers