[英]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();
引用类型在堆上分配,而值类型(例如int
、 struct
、 enum
)在堆栈或堆上,例如当定义为 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;
}
使用ref
或out
,为变量/字段分配新引用也将覆盖原始引用。 使用ref
时, out
或in
引用不再被视为副本而是别名(如 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.