Value passing and reference passing in C are resolved in detail

  • 2020-06-03 08:09:57
  • OfStack

1. Pass parameters
Parameters can be passed either by value or by reference. Passing arguments by reference allows function members (methods, properties, indexers, operators, and constructors) to change the value of an argument and keep that change.

2. Pass value type parameters
A value type variable contains its data directly, unlike a reference type variable, which contains a reference to its data. Therefore, passing a value-type variable to a method means passing a copy of the variable to the method. Changes to parameters that occur within a method have no effect on the raw data stored in the variable. If you want the called method to change the value of the parameter, you must pass it by reference using the ref or out keyword. For simplicity, the following example USES ref.

1. Value type passed by value:


class PassingValByVal
{
static void SquareIt(int x)
// The parameter x is passed by value.
// Changes to x will not affect the original value of x.
{
x *= x;
System.Console.WriteLine("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);
SquareIt(n); // Passing the variable by value.
System.Console.WriteLine("The value after calling the method: {0}", n);
}
} 

The variable n is a value type that contains its data (the value is 5). When SquareIt is called, the contents of n are copied to the parameter x, which is squared within the method. But in Main, the value of n is the same before and after calling the SquareIt method. In fact, changes within a method affect only the local variable x.

Pass the value type by reference
The following example is the same as the previous one except that the parameters are passed using the ref keyword. The value of the parameter changes after the method is called


class PassingValByRef
{
static void SquareIt(ref int x)
// The parameter x is passed by reference.
// Changes to x will affect the original value of x.
{
x *= x;
System.Console.WriteLine("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);
SquareIt(ref n); // Passing the variable by reference.
System.Console.WriteLine("The value after calling the method: {0}", n);
}
} 

In this example, instead of passing the value of n, you pass a reference to n. The parameter x is not of type int; it is a reference to int (in this case, n). Thus, when you square x in a method, what is actually being squared is the term referenced by x: n.

3. Exchanged value types
A common example of changing the value of a passed parameter is the Swap method, where two variables, x and y, are passed, and the methods are then made to exchange their contents. You must pass parameters to the Swap method by reference; Otherwise, what is processed within the method is a local copy of the argument. Here is an example of an Swap method using a reference parameter:


static void SwapByRef(ref int x, ref int y)
{
    int temp = x;
    x = y;
    y = temp;
}

3. Pass reference type parameters
A variable of a reference type does not directly contain its data; It contains references to its data. When passing a parameter of a reference type by value, it is possible to change the data that the reference points to, such as the value of a member of a class. But you cannot change the value of the reference itself; That is, you cannot use the same reference to allocate memory for a new class and keep it outside the block. To do this, pass the parameters using the ref or out keywords. For simplicity, the following example USES ref.

1. Pass the reference type by value
The following example demonstrates passing the reference type parameter arr to the Change method by value. Since this parameter is a reference to arr, it is possible to change the values of the array elements. However, when an attempt is made to reallocate the parameter to a different memory location, this only works within the method and does not affect the original variable arr.


class PassingRefByVal 
{
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
static void Main() 
{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);
Change(arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
}
} 

In the previous example, the array arr was a reference type passed to a method without using the ref parameter. In this case, a copy of the reference to arr is passed to the method. It is possible for the output display method to change the contents of the array elements, in this case from 1 to 888. However, using the new operator within the Change method to allocate a new part of memory causes the variable pArray to refer to the new array. Therefore, any changes after this will not affect the original array arr, which was created within Main. In fact, two arrays are created in this example, one in Main and one in the Change method.

Pass the reference type by reference
This example is the same as the previous example, except that the ref keyword is used in method headers and calls. Any changes that occur within a method affect the original variables in the calling program


class PassingRefByRef 
{
    static void Change(ref int[] pArray)
    {
        // Both of the following changes will affect the original variables:
        pArray[0] = 888;
        pArray = new int[5] {-3, -1, -2, -3, -4};
        System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
    }

    static void Main() 
    {
        int[] arr = {1, 4, 5};
        System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);
        Change(ref arr);
        System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
    }
}

All changes that occur within a method affect the original array in Main. In effect, the original array is reallocated using the new operator. Therefore, after calling the Change method, any reference to arr will point to an array of five elements created in the Change method.

3. Swap two strings
Swapping strings is a good example of passing reference type parameters by reference. In this example, the str1 and str2 strings are initialized in Main and passed to the SwapStrings method as parameters modified by the ref keyword. The two strings are exchanged within the method and within Main.


class SwappingStrings
{
static void SwapStrings(ref string s1, ref string s2)
// The string parameter is passed by reference.
// Any changes on parameters will affect the original variables.
{
string temp = s1;
s1 = s2;
s2 = temp;
System.Console.WriteLine("Inside the method: {0} {1}", s1, s2);
}
static void Main()
{
string str1 = "John";
string str2 = "Smith";
System.Console.WriteLine("Inside Main, before swapping: {0} {1}", str1, str2);
SwapStrings(ref str1, ref str2); // Passing strings by reference
System.Console.WriteLine("Inside Main, after swapping: {0} {1}", str1, str2);
}
} 

In this example, you need to pass parameters by reference to affect variables in the caller. If you remove the ref keyword from both the method header and the method call, nothing changes in the calling program.

4. Data value passing of reference type (copy passing)
The default of the class creates a shallow copy of the table with the MemberwiseClone method by creating a new object and then copying the non-static fields of the current object to the new object. If the field is of value type, the field is copied bit by bit. If the field is a reference type, copy the reference but not the referenced object; Therefore, the original object and its duplicate reference are the same as the 1 object. Deep copy, which implements the ICloneable interface.ICloneable can be used for both deep and shallow copies. These are concepts, but we need to understand:


   class ClassA : ICloneable
    {
        public string str;
        public SubClass subclass;
        public ClassA()
        {
            str = "classA str";
            subclass = new SubClass();
        }
        // Deep copy, multiple layers unavailable MemberwiseClone() Full implementation of deep replication 
        public object Clone()
        {
           // this.a = (string)this.a.Clone();
            //this.b = (B)this.b.Clone();
            var ne = new ClassA();
            ne.str = this.str;
            ne.subclass = (SubClass)this.subclass.Clone(); //this.b I still didn't succeed 
            return ne;
           // return this.MemberwiseClone();
        }
    }
    class SubClass : ICloneable
    {
        public string str;
        public SubClass()
        {
            this.str = "subclass str";
        }
        // Deep copy because only 1 Layers, so it works MemberwiseClone() methods 
        public object Clone()
        {
            this.str = (string)this.str.Clone();
            return this.MemberwiseClone();
        }


Related articles: