MST
星途 面试题库

面试题:C#指针操作与内存管理的深入理解

在C#中,当使用指针进行动态内存分配(例如使用`Marshal.AllocHGlobal`)后,如何正确地释放这些内存以避免内存泄漏?请举例说明在涉及指针操作的复杂数据结构(如链表)中,如何实现安全的内存管理和指针操作。
47.5万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试
  1. 释放Marshal.AllocHGlobal分配的内存
    • 使用Marshal.FreeHGlobal方法来释放通过Marshal.AllocHGlobal分配的内存。例如:
using System;
using System.Runtime.InteropServices;

class Program
{
    static void Main()
    {
        IntPtr ptr = Marshal.AllocHGlobal(100);
        try
        {
            // 在此处使用分配的内存
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }
    }
}
  1. 链表中安全的内存管理和指针操作
    • 首先定义链表节点结构,假设链表节点存储整数。
using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct ListNode
{
    public int Value;
    public IntPtr Next;
}
  • 以下是创建链表、释放链表内存的示例代码:
class LinkedListManager
{
    private IntPtr head;

    public void AddNode(int value)
    {
        IntPtr newNodePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ListNode)));
        ListNode newNode = new ListNode { Value = value, Next = IntPtr.Zero };
        Marshal.StructureToPtr(newNode, newNodePtr, false);

        if (head == IntPtr.Zero)
        {
            head = newNodePtr;
        }
        else
        {
            IntPtr current = head;
            while (Marshal.ReadIntPtr(current, Marshal.OffsetOf(typeof(ListNode), "Next").ToInt32()) != IntPtr.Zero)
            {
                current = Marshal.ReadIntPtr(current, Marshal.OffsetOf(typeof(ListNode), "Next").ToInt32());
            }
            Marshal.WriteIntPtr(current, Marshal.OffsetOf(typeof(ListNode), "Next").ToInt32(), newNodePtr);
        }
    }

    public void FreeList()
    {
        IntPtr current = head;
        while (current != IntPtr.Zero)
        {
            IntPtr next = Marshal.ReadIntPtr(current, Marshal.OffsetOf(typeof(ListNode), "Next").ToInt32());
            Marshal.FreeHGlobal(current);
            current = next;
        }
        head = IntPtr.Zero;
    }
}
  • 使用示例:
class Program
{
    static void Main()
    {
        LinkedListManager listManager = new LinkedListManager();
        listManager.AddNode(1);
        listManager.AddNode(2);
        listManager.AddNode(3);

        listManager.FreeList();
    }
}

在上述代码中:

  • AddNode方法中,为新节点分配内存,初始化节点值和Next指针,然后将新节点添加到链表末尾。
  • FreeList方法中,通过迭代链表,释放每个节点的内存,避免内存泄漏。同时,在整个操作过程中,使用Marshal类的方法进行指针操作和内存管理,确保安全。