离开课程后C#重置的指针

时间:2016-06-03 09:53:54

标签: c# pointers

我有一个班级Form1和一个班级MyList。我想创建一个程序,将字符放入List并有一个指针,显示在下一个。 我的问题是每次调用类MyList时,指针都会重置。

我该如何解决这个问题。 这是一个学校项目,必须以这种方式完成,使用指针

感谢所有答案!

namespace Data {
    public partial class Form1 : Form
    {
        char character = "a"
        int index = 0;
        MyList a = new MyList();
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)   //On click get new index and character and put in a List.
        {
           a.PutIn(index, character);
        }   
    } 
}

MyList类:

namespace Data
{
    public unsafe struct list
    {
        public char x;
        public list* next;
    }
    public unsafe partial class MyList
    {
        list* first = null;
        list* last = null;
        int index;
        public unsafe MyList() { Initialize(); }

        public unsafe void Initialize() 
        {
            first = null;
            last = null;
            index = -1;
        }
        ~MyList()
        { 
            do{
                Emty(0);
            }while (!IsEmpty());
        }
        public unsafe void PutIn(int place, char character) 
        { 
        if (((index+1)<place)||(place<0))
           MessageBox.Show("Index is too high!");
        else
        {
            if (IsEmpty()) 
            {
                list temp = new list();
                list* temp_pointer = &temp;
                temp_pointer->next = null;
                temp_pointer->x = character;
                first = temp_pointer;
                last = temp_pointer;
                temp_pointer = null;
                index++;
            }
            else if (place == (index + 1)) 
            {
                list temp = new list();
                list* temp_pointer = &temp;
                temp_pointer->next = null;
                temp_pointer->x = character;
                last->next = temp_pointer;
                last = temp_pointer;
                temp_pointer = null;
                index++;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

问题在于您将list分配为本地,并且不能保证其持续时间超过定义它的范围(实际上,保证仅对托管代码有意义 - 如果想要的话,运行时编译器可以在范围结束之前很久就摆脱它。

你真的想要将对象分配到会持续更长时间的地方。最简单的方法是使用Marshal.AllocHGlobal在非托管堆上分配一些内存。您可以使用Marshal.FreeHGlobal释放该内存。这大致相当于在C中使用newdelete

我从你的代码示例开始,但不得不改变一些事情以避免发疯。这并不意味着最终样本是100%正确的或者是实现这一目标的好方法,我仍然只是改变代码中的一些东西以使其工作。在一个真正的实现中,我会使整个事情有所不同 - 如果您对使用C#和C#(或一般)指针的一些好习惯感兴趣,您可能想要发布完整的,代码审查的工作代码 - 你会在那里得到很多好的反馈。

示例代码,包括在列表中添加和删除项目:

void Main()
{
  var list = new MyList();
  list.InsertAt(0, 'A');
  list.InsertAt(1, 'B');
  list.InsertAt(2, 'C');
  list.InsertAt(1, 'X');

  Console.WriteLine(string.Join(", ", list.Select(i => i.ToString())));

  list.RemoveAt(1);

  Console.WriteLine(string.Join(", ", list.Select(i => i.ToString())));
}

public unsafe struct list
{
    public char x;
    public list* next;
}

public unsafe class MyList : IEnumerable<char>
{
  list* first;
  list* last;
  int count;

  public int Count { get { return count; } }
  public bool IsEmpty() { return count == 0; }

  private void Remove(list* previous, list* current)
  {
    if (first == current) first = current->next;
    if (last == current) last = previous;
    if (previous != null) previous->next = current->next;

    Console.WriteLine
      (
        "Removing {0}, first {1}, last {2}, count {3}", 
        current->x, 
        first == null ? '-' : first->x, 
        last == null ? '-' : last->x,
        count
      );

    count--;
    Marshal.FreeHGlobal(new IntPtr(current));
  }

  public void RemoveAt(int index)
  {
    if (count < index || index < 0)
      throw new ArgumentOutOfRangeException("Index is out of range!");

    var current = first;

    if (index == 0)
    {
      Remove(null, current);

      return;
    }

    for (var i = 0; i < index - 1; i++)
    {
      current = current->next;
    }

    Remove(current, current->next);
  }

  ~MyList()
  { 
      do
      {
        RemoveAt(0);
      }
      while (!IsEmpty());
  }

  private list* InsertAfter(list* previousItem, char character)
  {   
    var newItem = (list*)Marshal.AllocHGlobal(sizeof(list));
    newItem->next = previousItem == null ? null : previousItem->next;
    newItem->x = character;

    if (previousItem == last) last = newItem;
    if (previousItem != null) previousItem->next = newItem;

    count++;

    Console.WriteLine
      (
        "Added {0} after {1}, first {2}, last {3}, count {4}",
        character,
        previousItem == null ? '-' : previousItem->x,
        first == null ? '-' : first->x,
        last == null ? '-' : last->x,
        count
      );

    return newItem;
  }

  public void InsertAt(int index, char character) 
  { 
    if (count < index || index < 0)
      throw new ArgumentOutOfRangeException("Index is out of range!");

    if (index == 0)
    {
      var newItem = InsertAfter(null, character);
      if (first != null) newItem->next = first;
      first = newItem;
    }
    else if (index == 1) 
    {
      InsertAfter(first, character);
    }
    else if (index == count) 
    {
      InsertAfter(last, character);
    }
    else
    {
      var current = first;
      for (var i = 0; i < index - 2; i++)
      {
        current = current->next;
      }

      InsertAfter(current, character);
    }
  }

  private class MyListEnumerator : IEnumerator<char>
  {
    private MyList list;
    private list* current;

    public MyListEnumerator(MyList list)
    {
      this.list = list;
      this.current = null;
    }

    public void Reset() { current = null; }

    public bool MoveNext()
    {
      if (current == null) current = list.first;
      else current = current->next;

      return current != null;
    }

    public char Current
    {
      get
      {
        if (current == null) throw new InvalidOperationException();

        return current->x;
      }
    }

    object IEnumerator.Current { get { return (object)Current; } }

    public void Dispose() {}
  }

  public IEnumerator<char> GetEnumerator() { return new MyListEnumerator(this); }
  IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}