предыдущий указатель не работает для моего стека с помощью GList - PullRequest
0 голосов
/ 23 апреля 2020

Я реализую стек, используя GList (вдвойне), но когда я назначаю свой стек последним элементом, используя g_list_last(*stack*), программа вообще не печатает мой стек

Указывая на первый элемент, используя g_list_first(*stack*) работает, и я могу перемещаться с помощью стека-> следующий указатель

Вот моя тестовая программа:

#include <iostream>
#include <cstdlib>
#include <glib.h>

using namespace std;

int main()
{
        cout << "Enter the no of random data to push: ";
        int number = 0;
        cin >> number;

        GList *stack = nullptr;
        for (int i = 0; i < number; i++) {
                int data = random() % 10;
                stack = g_list_append(stack, GINT_TO_POINTER(data));
                cout << "Push: " << data << endl;
        }

        cout << "Printing the stack forward:\n";
        stack = g_list_first(stack);
        while (stack != nullptr) {
                cout << GPOINTER_TO_INT(stack->data);
                cout << "->";
                stack = stack->next;
        }
        cout << "nullptr" << endl;

        cout << "Printing the stack backward:\n";
        stack = g_list_last(stack);
        while (stack != NULL) {
                cout << GPOINTER_TO_INT(stack->data);
                cout << "->";
                stack = stack->prev;
        }
        cout << "nullptr" << endl;

        return 0;
}

Нужно ли вручную назначать ссылку prev при добавлении?

1 Ответ

0 голосов
/ 23 апреля 2020

Прежде всего, я бы не рекомендовал использовать GLib в базе кода C ++; GLib - это библиотека C, полная идиоматического c C кода и функциональности. Вместо этого я бы предложил использовать стандартную библиотеку C ++.

GList - это двусвязный список, каждый элемент которого состоит из трех указателей:

typedef struct _GList GList;
struct _GList
{
  void *data; // untyped pointer data
  GList *prev; // pointer to the previous element in the list
  GList *next; // pointer to the next element in the list
}

Для удобства все функции GList принимают NULL в качестве допустимого списка; в случае g_list_append() передача списка NULL в качестве первого аргумента означает, что он выделит новый элемент GList для передаваемых данных и поместит его в начало списка.

В своем коде вы берете заголовок списка после его заполнения и вызываете g_list_first(), что является запретом в начале списка; затем вы продолжаете использовать его, перебирая его, пока не дойдете до конца списка, где вы присваиваете nullptr переменной stack. Поскольку nullptr / NULL является действительным пустым GList, теперь вы вызываете g_list_last() для действительного, но пустого списка, который вернет NULL и, таким образом, не позволит вам выполнить итерацию в обратном направлении. Кроме того, теперь вы теряете память, выделенную для списка.

Решение состоит в том, чтобы никогда не повторять GList с той же переменной, которая содержит заголовок списка:

        cout << "Printing the stack forward:\n";
        GList *iter = g_list_first(stack);
        while (iter != nullptr) {
                cout << GPOINTER_TO_INT(iter->data);
                cout << "->";
                iter = iter->next;
        }
        cout << "nullptr" << endl;

Приведенный выше код будет использовать переменную iter вместо stack. Это означает, что приведенный ниже код:

        cout << "Printing the stack backward:\n";
        iter = g_list_last(stack);
        while (iter != NULL) {
                cout << GPOINTER_TO_INT(iter->data);
                cout << "->";
                iter = iter->prev;
        }
        cout << "nullptr" << endl;

будет работать надлежащим образом и перемещаться по стеку назад, поскольку переменная stack по-прежнему указывает на начало списка, и теперь вы используете временный итератор .

Не забудьте вызвать g_list_free() в списке, чтобы высвободить все ресурсы, выделенные для него, и g_list_free_full() в случае, если вы также выделяете содержимое указателя data.

...