繁体   English   中英

memory 如何在具有变量分配的 c# 中工作?

[英]How does memory work in c# with variable assignment?

我正在处理一些编程问题以准备面试,但我对一个可行的解决方案感到困惑。

问题本身并不重要,重要的是在这个解决方案中,一个变量设置为另一个变量,例如:

ListNode current = head;

然后随着解决方案的继续,这个“当前”变量被修改。 在任何时候都不会将 current 重新分配给 head ,但它仍然会在最后返回 head 以及对 current 所做的所有更改。

while (current != null && current.next != null) {
        if (current.next.val == current.val) {
            current.next = current.next.next;
        } else {
            current = current.next;
        }
}
return head;

这是否意味着当 current 设置为 head 时,它实际上被设置为指向 memory 地址的指针,而不是复制相同的属性?

我很尴尬,因为我不明白这里发生了什么,但除非我确信我知道发生了什么,否则我觉得继续前进并不舒服。

谢谢

它不是指针,它在 C# 中的引用。

是的,它们将指向相同的 memory 地址。 下面我给你一个简单的例子。

using System;
            
public class Program
{
    public class ABC {
    public int x;
    }
    public static void Main()
    {
        ABC a = new ABC();
        a.x = 1;
        ABC b = a;
        b.x = 2;
        ABC c = b;
        c.x = 3;
        Console.WriteLine(a.x);
        Console.WriteLine(b.x);
        Console.WriteLine(b.x);
    }
}

它将打印。

3

3

3

它称为按引用复制。 C# 拥有 object 类型:值类型和引用类型。

创建 object 的实例会分配 memory:

new MyClass();

引用类型在堆上分配,而值类型(例如intstructenum )在堆栈或堆上,例如当定义为 class 成员时。
对这个分配的 memory(值)的引用也存储在堆栈中。

您可以查看变量和字段(和属性)作为参考。

如前所述,C# 知道引用类型和值类型。 两者在引用它们的方式或处理它们的引用的方式上都不同。

引用类型

对于引用类型,默认情况下始终复制引用 与 C++ 不同,指针 C# 引用不相等但指向相同的 memory ZA8CFDE6331BD54B66AC96F8911。 This means every reference or variable is an individual object on the stack (unlike C++, where each pointer variable is actually an alias of the same pointer), but all copies point to the same memory object ie memory location ie value.

将引用类型的实例分配给变量/字段/属性会将引用复制到实例分配的 memory 即值:

// Let local variable 'a' point to/reference instance of MyClass (the value)
var a = new MyClass();

将变量/字段/属性分配给另一个变量/字段/属性只会复制对 memory 位置的引用而不是值

// Let local variable 'a' point to/reference an instance of MyClass (the value)
var a = new MyClass();

// Let reference 'b' point to/reference the same instance/value/memory location of 'a' 
MyClass b = a;

bool areEqual = object.ReferenceEquals(a, b); // true

对于引用类型,分配变量/字段/属性就像复制实际的指针/引用。 由于此引用只是一个副本而不是别名,因此修改一个引用不会修改所有现有引用(与 C++ 中的指针不同):

// Let local variable 'a' point to/reference an instance of MyClass (the value)
var a = new MyClass();

// Let 'b' point to/reference the *same* instance/value/memory location of 'a' 
MyClass b = a;

bool areEqual = object.ReferenceEquals(a, b); // true

// Let 'b' reference a second instance. 
// But 'a'  will still reference the first instance.
b = new MyClass();

areEqual = object.ReferenceEquals(a, b); // false  

MyClass d = ChangeValue(a);
areEqual = object.ReferenceEquals(a, d); // false  

private MyClass ChangeValue(MyClass c)
{
  // true (because 'c' is a copy 0f 'a')
  bool areEqual = object.ReferenceEquals(a, c); 

  // Let 'c' point to a new memory location/value
  c = new MyClass();

  // false (because 'c' and 'a' are no longer pointing to the same memory/instance/value)
  areEqual = object.ReferenceEquals(a, c);   
  return c;
}

使用refout ,为变量/字段分配新引用也将覆盖原始引用。 使用ref时, outin引用不再被视为副本而是别名(如 C++ 指针变量)。 修改别名会修改引用的所有其他现有别名:

// Let local variable 'a' point to/reference an instance of MyClass (the value)
var a = new MyClass();

// Let 'b' point to/reference the same instance/value/memory location of 'a' 
MyClass b = a;

bool areEqual = object.ReferenceEquals(a, b); // true

// Let 'b' reference a second instance. But 'a'  will still reference the first instance.
b = new MyClass();

areEqual = object.ReferenceEquals(a, b); // false  

MyClass d = ChangeValue(ref a);
areEqual = object.ReferenceEquals(a, d); // true (because of 'ref')

// Parameter declared as ref
private MyClass ChangeValue(ref MyClass c)
{
  // true (because 'c' is a copy 0f 'a')
  bool areEqual = object.ReferenceEquals(a, c); 

  // Let 'c' point to a new memory location/value.
  // Because of 'ref' 'c' is no longer a copy of 'a', 
  // but an alias (same reference).
  // Overwriting 'c'  will overwrite 'a' too.
  c = new MyClass();

  // true (because 'c' and 'a' are still pointing to the same memory.
  // Because of 'ref' 'c' is an alias of 'a').
  areEqual = object.ReferenceEquals(a, c); // true
  return c;
}

值类型

对于类型,默认情况下始终复制值。 这意味着与引用类型相反,其中复制了对值(内存位置)的引用,复制了值或 memory 位置本身:

// Create a new instance of a value type (struct in this case)
var p1 = new Point();

// Assign a copy of the value to a new reference
var p2 = p1;

// false (because both reference point to different memory locations) 
var areEqual = object.ReferenceEquals(p1, p2); // false 

Point p4 = ChangeValue(ref p2);
areEqual = object.ReferenceEquals(p2, p4); // false (because different memory location)

private MyClass ChangeValue(Point p3)
{
  // false (because 'p3' points to a different memory location than 'p2' - value is copied)
  bool areEqual = object.ReferenceEquals(p3, p2); 

  // Let 'p3' point to a new memory location/value.
  p3 = new Point();

  // false (because 'p3' points to adifferent memory location than 'p2')
  areEqual = object.ReferenceEquals(p2, p3); // true
  return p3;
}

使用 'ref'、'out' 或 'in' 将创建引用值的副本:

// Create a new instance of a value type (struct in this case)
var p1 = new Point(1, 1);

// Assign a copy of the value to a new reference
var p2 = p1;

// false (because both reference point to different memory locations) 
var areEqual = object.ReferenceEquals(p1, p2); // false 

// But their data equals
var isEqual = p1 == p2; // true

Point p3 = ChangeValue(ref p2);
areEqual = object.ReferenceEquals(p2, p3); // false (different memory)

areEqual = p2 == p3; // true (same value)

// Parameter declared as ref
private MyClass ChangeValue(ref Point p3)
{
  // false (because 'p3' and 'p2' point to different memory locations i.e. values)
  bool areEqual = object.ReferenceEquals(p3, p2); 

  // Let 'p3' point to a new memory location/value.
  // Because of 'ref' overwriting 'p3'  will overwrite 'p2' too.
  // But since both are value types they actually reference a copy of the same value at different memory locations.
  p3 = new Point(5, 5);

  // false (because 'p3' and 'p2' are pointing to different memory.
  areEqual = object.ReferenceEquals(p2, p3); // true

  // Only the value/data was copied.
  areEqual = p2 == p3; // true

  return p3;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM