【问题标题】:prev pointer not working for my stack using GList使用 GList 的 prev 指针不适用于我的堆栈
【发布时间】:2020-04-23 11:22:56
【问题描述】:

我正在使用 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;
}

我必须在附加时手动分配上一个链接吗?

【问题讨论】:

  • 我对 glist 了解不多,但我怀疑,由于将未初始化的指针传递给 g_list_append,您正在调用未定义的行为。
  • @AlgirdasPreidžius 刚刚将 nullptr 分配给我的堆栈并现在对其进行测试。不,问题仍然存在:(
  • 未定义的行为并不意味着它总是会破坏行为。它也可能以您期望的方式工作。因此,在上述修复之后,您的代码很可能有一个问题,而不是两个。
  • 更新代码:)以避免错误

标签: c++ stack glib


【解决方案1】:

首先,我不建议在 C++ 代码库中使用 GLib。 GLib 是一个 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() 以释放分配给它的所有资源——如果你还要分配data 指针的内容,还需要调用g_list_free_full()

【讨论】:

  • 非常感谢您的解决方案 + 对 GLib 和我的代码泄漏内存的更多见解 :)
猜你喜欢
  • 2019-08-27
  • 2013-11-06
  • 1970-01-01
  • 1970-01-01
  • 2015-11-16
  • 1970-01-01
  • 2013-01-20
  • 2014-06-21
  • 1970-01-01
相关资源
最近更新 更多