Good day! It is required to create a linked list of structure objects in which the current element should point to the next one, the last one to null. In C ++, when I did this, there were no problems. In C #, the first element is created without problems. But the second is created with the same address! How to fix it?

// Структура объектов очереди struct QueueItem { public int Value; public unsafe QueueItem* Next; public unsafe QueueItem(int value) : this() { Value = value; Next = null; } } class QueueWithMinStats { private unsafe QueueItem* _first; private unsafe QueueItem* _last; public unsafe QueueWithMinStats() { _first = null; _last = null; } // Добавить в очередь значение public unsafe void Enqueue(int value) { // Проблема тут!!! var newItem = new QueueItem(value); var newItemLink = &newItem; if (_first == null) // Если вводимый элемент - первый _first = newItemLink; else _last->Next = newItemLink; _last = newItemLink; } } 
  • If interested, you can see how LinkedList is implemented in .Net
  • You should not use unsafe if you do not understand what this keyword means. And native pointers. Otherwise, you yourself create a problem. - VladD 5:09

1 answer 1

With reference to the structure, the new operator does not allocate memory, but only calls the constructor. The structure itself is created on the stack in the same place each time - it’s not surprising that the pointers are the same.

In order for the structure to be "transferred" to the heap - it is necessary to cast it to the object type (this operation is called packaging). But it’s not so easy to get an address from a packed structure using language means ...

Therefore, I suggest you do everything differently.

First, replace the structure with a class (meaningful type with reference). Second, remove the pointers: they are not needed for reference types.

Together with other, not so critical, corrections, it will turn out somehow like this:

 class QueueWithMinStats { class QueueItem // я перенес этот класс внутрь, потому что за пределами реализации очереди он никому не должен быть интересен { public int Value; public QueueItem Next; public QueueItem(int value) { Value = value; // Next инициализаровать не надо - поля классов инициализируются значениями по умолчанию автоматически } } private QueueItem _first; private QueueItem _last; // Конструктор пока не нужен public void Enqueue(int value) { // Проблемы больше нет!!! var newItem = new QueueItem(value); // Переменная newItemLink больше не нужна - потому что QueueItem - это ссылочный тип if (_first == null) // Если вводимый элемент - первый _first = newItem; else _last.Next = newItem; _last = newItem; } }