References
Up to now you've seen how basic applications can be implemented easily. In those applications, we accessed variables directly and modified them without worrying about anything else.
However, in many cases, it's necessary to pass values to other procedures. This usually isn't a problem, but in some cases it leads to some new circumstances that you have to deal with:
using System; public class Demo { public static void Main() { int x = 3; int y = 5; Swap(x, y); Console.WriteLine("x: {0} - y: {1}", x, y); } static void Swap(int a, int b) { int c = a; a = b; b = c; Console.WriteLine("a: {0} - b: {1}", a, b); } }
We define two variables inside the main program. The target of the method called Swap is to change the content of those values. Both variables are passed to the function. Inside the function, we try to swap the content of the variables. Finally, we display the result. Let's see which result you can expect:
[hs@duron csharp]$ mono ref.exe a: 5 - b: 3 x: 3 - y: 5
The values are obviously still in the same order. The reason for that is fairly simple to explain. When Swap is started, both values are allocated on the stack. In other words, the system creates a copy of the two values. We swap the copies and the function is terminated. This does not affect the original data.
To get rid of the problem, we have to use what are known as references. The following piece of code shows how the problem can be solved with the help of C:
#include <stdio.h> void swap(int *a, int *b) { int c = *a; *a = *b; *b = c; printf("a: %d - b: %d\n", *a, *b); } int main() { int x = 3; int y = 5; swap(&x, &y); printf("x: %d - y: %d\n", x, y); return 0; }
The main program passes the address of the variable to the function. The address is the location of a certain piece of data in memory. In that way, the function can access and modify the data directly in memory.
The output of the problem will look like this:
[hs@duron csharp]$ gcc ref.c [hs@duron csharp]$ ./a.out a: 5 - b: 3 x: 5 - y: 3
The system changes the values and displays them on screen. After this small excursion into the world of C, we'll get back to a simple C# application. The following listing shows how the problem we just discussed can be solved by means of C#:
using System; public class Demo { public static void Main() { int x = 3; int y = 5; Swap(ref x, ref y); Console.WriteLine("x: {0} - y: {1}", x, y); } static void Swap(ref int a, ref int b) { int c = a; a = b; b = c; Console.WriteLine("a: {0} - b: {1}", a, b); } }
When passing the data to the function, we mark it as a reference. The method accepting the data must know that the variable is a reference, so it has to be mentioned in the head of the function as well. The syntax provided by C# makes it much more pleasant to work with pointers than in C. Many of those among you who have experience with C will know what we're talking about. The source of trouble is minimal and it isn't that easy to induce troubles caused by pointers.
In the next listing, we'll see how variables can be swapped correctly:
[hs@duron csharp]$ mono ref.exe a: 5 - b: 3 x: 5 - y: 3
Working with references is easy and does not lead to many troubles. C# and the Mono framework provide pointers as well. We'll talk about pointers when we get to unsafe code and including C code in C# in Chapter 16.