Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

C# Проблема с указателями при создании связного списка

#c_sharp #указатели


Добрый день!
Требуется создать связный список объектов структуры, в котором текущий элемент должен
указывать на следующий, последний - на null. На C++ когда делал подобное - проблем
не возникло. На C# первый элемент создается без проблем. Но второй создается с тем-же
адресом! Как это исправить?

// Структура объектов очереди
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;        

    }
}

    


Ответы

Ответ 1



Применительно к структуре, оператор new не выделяет память, а лишь вызывает конструктор. Сама структура каждый раз создается на стеке в одном и том же месте - неудивительно что указатели одинаковы. Для того, чтобы структура "перенеслась" в кучу - надо кастануть ее к типу object (эта операция называется упаковкой). Но у упакованной структуры получить адрес средствами языка - не так-то и просто... Поэтому предлагаю вам сделать все по-другому. Во-первых, замените структуру на класс (значимый тип на ссылочный). Во-вторых, уберите указатели: для ссылочных типов они не нужны. Вместе с другими, не столь критичными, исправлениями, получится как-то так: 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; } }

Комментариев нет:

Отправить комментарий