在C#(不安全构造)中使用结构实现链表时获取垃圾值

在C#(不安全构造)中使用结构实现链表时获取垃圾值,c#,struct,unsafe,C#,Struct,Unsafe,我试图验证我的一个朋友报告的行为,所以我使用struct在C#中实现了单链表。因为我必须使用指针,所以我使用了C#提供的不安全构造。我还在项目属性的build选项卡中将属性设置为允许不安全代码,以使代码可编译 以下是我的完整代码实现: public unsafe struct NodeList { public Node* head; public Node* current; public void AddNode(int d) { Node

我试图验证我的一个朋友报告的行为,所以我使用struct在C#中实现了单链表。因为我必须使用指针,所以我使用了C#提供的不安全构造。我还在项目属性的build选项卡中将属性设置为
允许不安全代码
,以使代码可编译

以下是我的完整代码实现:

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.nullreferenceexception
    exception。两个节点都应正确打印数据

  • 现在,我得到的行为可能是由于我在代码中犯了一个错误,也可能是因为我使用的是托管世界中的指针。我需要您的帮助来解决这个问题。

    使用本机
    封送.AllocHGlobal
    分配内存(类似于C中的malloc)


    注意:您还需要使用
    封送。FreeHGlobal
    释放内存。当head为null时,head和current都指向相同的内存位置。所以两者都成为指向相同内存地址的指针。 添加第二个节点时,您正在更改当前指针指向的值,但由于头部也指向相同的值,所以它也会随当前值而更改


    我是通过阅读您的代码得出这个结论的,所以我可能不正确。但是这似乎是原因。

    为什么C标签是C??这个问题和C或C++有什么关系?请不要用不相关的标签发送垃圾邮件。已更新的标签。删除C和C++。我认为这是关于指针和不安全的东西,所以添加了C和C++。至于你的问题,在<代码> AddNode < /C> >不是函数<代码> n>代码>函数中的局部变量,一个函数返回后的范围内的局部变量?发生这种情况时,指向该局部变量的指针会发生什么情况?它们指向哪里?您正在存储指向堆栈分配变量的指针,因此得到垃圾也就不足为奇了。在函数内部执行此操作本质上是在堆栈上进行内存分配,因为
    节点是一个结构。函数结束时,内存分配消失,因为堆栈顶部指针将向后移动。您无法控制在未分配的孤立内存区域上写入的内容。我不得不使用Richa的
    Node*newNode=(Node*)Marshal.AllocHGlobal(sizeof(Node)).ToPointer()
    code在程序的
    Heap
    内存区域上进行分配,以在
    AddNode
    函数执行完成后将其持久化。
    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();
        }
     }
    }