Parameter Passing: By Value vs. By Reference

Posted by: Clarity Blogs: ASP.NET, on 17 Jun 2009 | View original | Bookmarked: 0 time(s)

I was reading some old posts on Wil Shipleys excellent blog the other day, when a subtle (and very common) error caught my eye. I dont mean to call Wil out by this; I was reading his blog specifically because I think he has great advice about software development. The error in question was talking about some of the problems with the outdated Carbon framework that much of Apples older software is built on. The following caught my eye:

Parameters passed into functions are passed by reference, whether they are going to be modified or not, which is just obscure. For example, see SecKeychainItemCopyAttributesAndData(), which takes the input "info" by reference, even though it's read-only!

For those who dont know, the Carbon framework is written (I believe completely) in C. Can you spot the semantic error? The following quote from K & R will explain:

In preparing for the call to a function, a copy is made of each argument; all argument-passing is strictly by value. A function may change the values of its parameter objects, which are copies of the argument expressions, but these changes cannot affect the values of the arguments. However, it is possible to pass a pointer on the understanding the function may change the value of the object to which the pointer points.

In C, every parameter is passed by value. Now, Im sure Wil knows the this and simply misspoke, but a lot of people make this mistake, so Id like to take the time to explain the difference.

All parameters in C are passed by value. This means that, when a function is invoked, copies are made of each of its arguments for the function to use freely. When we say a parameter has been passed by reference, we mean that the function has received the actual object passed to it and not a copy. Its easy to mistakenly believe C includes this concept because C++ does; one being a (not quite strict) superset of the other, it takes familiarity with both to know where one stops and the other begins. What Wil is really talking about when he mentions passing parameters by reference is passing pointers by value. While the function receives a copy of the pointer passed to it, both still point to the same location in memory. The function can then make changes to the memory pointed to, which the caller will see. This is how shared references between function and caller are done in C. (This also makes the benefits of C++s added pass by reference semantics a little unclear to me.) Lets explore the differences with a couple concrete examples.

#include <stdio.h>

void chgval(int *ip)
{
    printf("*ip in chgval before change: %d\n", *ip);
    *ip = 5;
    printf("*ip in chgval after change: %d\n", *ip);
}

int main(int argc, char **argv)
{
    int i = 3;
    int *ip;
    ip = &i;
    printf("*ip before chgval: %d\n", *ip);
    chgval(ip);
    printf("*ip after chgval: %d\n", *ip);
    return 0;
}

Here we define a pointer to an int (ip) and assign to it the address of an int (i). If youre not familiar with the semantics of C, just know that, in this example, ip refers to the address of an int, whereas *ip is the int itself. Inside the chgval function, we assign a new value to *ip. Note that the address it points to is unchanged, so this reassignment can bubble back up to the caller. When we run this program, we see the expected output:

image

However, if you dont know that parameters in C are passed by value, you might attempt to make other changes.

#include <stdio.h>

void chgptr(int *ip)
{
    printf("*ip in chgptr before change: %d\n", *ip);
    int i = 5;
    ip = &i;
    printf("*ip in chgptr after change: %d\n", *ip);
}

int main(int argc, char **argv)
{
    int i = 3;
    int *ip;
    ip = &i;
    printf("*ip before chgptr: %d\n", *ip);
    chgptr(ip);
    printf("*ip after chgptr: %d\n", *ip);
    return 0;
}

This code is similar, but it attempts to reassign the pointer itself in the chgptr function. This works, but only within the scope of the function. Since the parameter is a copy of the original pointer, we see this output:

image

The original pointer remains untouched.

These examples have been in C, but the concepts are still important to .NET developers. This is because C# has the unrelated concepts of value/reference types and passing parameters by value/reference. The former is used to talk about what happens when we copy some object. Do we copy its value, or do we just copy a reference to it? The latter is what weve been discussing in C, except C# does include the concept of passing parameters by reference (using the ref keyword). Consider the following code:

static void Main(string[] args)
{
    object o = "original";
    ChangeObject(o);
    Console.WriteLine(o);
}

static void ChangeObject(object o)
{
    o = 5;
}

You might know that objects in C# are copied by reference and expect the change inside our function call to persist after it returns. Not so! The parameter is still passed by value. What you really need is this:

static void Main(string[] args)
{
    object o = "original";
    ChangeObject(ref o);
    Console.WriteLine(o);
}

static void ChangeObject(ref object o)
{
    o = 5;
}

This specifies that the parameter should be passed by reference.

Im sure this is common knowledge to a lot of people, but Ive heard it explained incorrectly enough times that I wanted to clarify.

Hope this helps.

Advertisement
Free Agile Project Management Tool from Telerik
TeamPulse Community Edition helps your team effectively capture requirements, manage project plans, assign and track work, and most importantly, be continually connected with each other.
Category: C# | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 1910 | Hits: 35

Similar Posts

  • My History of Visual Studio (Part 10, final) more
  • My History of Visual Studio (Part 9) more
  • LINQ to SQL, Lazy Loading and Prefetching more
  • Chat room questions from the EF Tips & Tricks webcast more
  • Visual Studio Add-In vs. Integration Package Part 1 more
  • Silverlight 3 object tag param list (aka Where is my asp:Silverlight control?) more
  • Building Silverlight 2 and 3 applications with Visual Studio 2008 more
  • VS2010 Beta 1 - It's Better on Metal more
  • .NET 4.0 -- System.Runtime.CompilerServices.ConditionalWeakTable more
  • Checking for EF to TSQL Query Compilation Changes in VS2010 Beta1 more

News Categories

.NET | Agile | Ajax | Architecture | ASP.NET | BizTalk | C# | Certification | Data | DataGrid | DataSet | Debugger | DotNetNuke | Events | GridView | IIS | Indigo | JavaScript | Mobile | Mono | Patterns and Practices | Performance | Podcast | Refactor | Regex | Security | Sharepoint | Silverlight | Smart Client Applications | Software | SQL | VB.NET | Visual Studio | W3 | WCF | WinFx | WPF | WSE | XAML | XLinq | XML | XSD