在c#中使用结构体实现链表时获取垃圾值(不安全结构)
本文关键字:不安全 结构 获取 结构体 链表 实现 | 更新日期: 2023-09-27 18:04:41
我试图验证我的一个朋友报告的行为,所以我在c#中使用struct实现单链表。因为我必须使用指针,所以我使用了c#提供的不安全结构。我还将项目属性的build选项卡中的属性设置为Allow unsafe code
,以使代码可编译。
这是我完整的代码实现:
public unsafe struct NodeList
{
public Node* head;
public Node* current;
public void AddNode(int d)
{
Node n = new Node();
n.data = d;
n.link = null;
if (head == null)
{
head = current = &n;
}
else
{
(*current).link = &n;
current = &n;
}
Console.WriteLine(head->data);
}
public void TraverseNodes()
{
Node* temp = head;
while(temp != null)
{
Console.WriteLine(temp -> data);
temp= temp -> link;
}
}
}
public unsafe struct Node
{
public int data;
public Node* link;
}
class Program
{
private static void UnsafeDSImplementation()
{
var myLinkedList = new NodeList();
myLinkedList.AddNode(2);
myLinkedList.AddNode(4);
myLinkedList.TraverseNodes();
}
static void Main(string[] args)
{
UnsafeDSImplementation();
}
}
的观察:
- 每次我进入
AddNode
方法并尝试打印节点数据值时,第一次我得到2,第二次我得到4。我想知道当我在添加第一个节点时只分配一次时,头部是如何变化的。 - 在遍历所有节点时-我获得第一个节点的数据值为2243610(这在每次运行时都在变化,所以它是垃圾)和
System.NullRefernceException
异常用于第二个节点迭代。两个节点都应该正确打印数据。
现在我得到的行为可能是由于我在代码中犯了一个错误,或者可能是很明显的,因为我正在使用来自托管世界的指针。我需要你的帮助来解决这个问题
使用本地Marshal.AllocHGlobal
(类似于C中的malloc)分配内存
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Linked_List
{
public unsafe class NodeList
{
public static Node * head ;
public void AddNode(int d)
{
Node* newNode = (Node*)Marshal.AllocHGlobal(sizeof(Node)).ToPointer();
newNode->data = d;
newNode->link = null;
Node* temp;
if (head == null)
{
head = newNode;
}
else
{
temp = head;
head = newNode;
newNode->link = temp;
}
Console.WriteLine(head->data);
}
public void TraverseNodes()
{
Node* temp = head;
while (temp != null)
{
Console.WriteLine(temp->data);
temp = temp->link;
}
}
}
public unsafe struct Node
{
public int data;
public Node* link;
}
unsafe class Program
{
private static void UnsafeDSImplementation()
{
var myLinkedList = new NodeList();
myLinkedList.AddNode(2);
myLinkedList.AddNode(4);
myLinkedList.TraverseNodes();
}
static void Main(string[] args)
{
UnsafeDSImplementation();
}
}
}
注意:您还需要使用Marshal.FreeHGlobal
看起来当head为null时,head和current都指向相同的内存位置。所以它们都变成了指向相同内存地址的指针。当第二个节点被添加时,你正在改变当前指针指向的值,但由于头部也指向相同的值,它也会随着当前的变化而变化。
我只是通过阅读你的代码才得出这个结论,所以我可能不正确。但这似乎就是原因。