【问题标题】:Freeing the temp node when adding to a linkedlist添加到链表时释放临时节点
【发布时间】:2019-10-28 16:46:25
【问题描述】:

我有一个名为addMod 的函数,调用该函数时,会将一个节点添加到Module 结构LinkedLists 数组的某个索引,该数组称为modules,包含在System 结构中。 Module 结构有一个字符串字段、两个 int 字段和一个指向下一个 Module 的指针,前三个字段根据 addMod 中提供的参数进行初始化。 addMod大致是这样的:

int addMod(System *system, const char *text, int num1, int num2, int index) {
    Module *temp = malloc(sizeof(Module));
    Module *current;
    temp->next = NULL;

    if ([any of the constructors are invalid]) return 0;

    temp->text = malloc(strlen(text)+1);
    strcpy(temp->text, text);
    temp->num1 = num1; temp->num2 = num2;

    if (!system->modules[index]) {
        system->modules[index] = temp; //If there are no modules in the LinkedList at the given index, makes the head = temp.
    }
    else {
        if (system->compare(temp, system->modules[index]) <= 0) { //compare is a func pointer field of system that compares two Modules to see in what order they should be. Here, we check if temp should become the head of modules[index].
            temp->next = system->modules[index]; //Assigns the current head as the module following temp.
            system->modules[index] = temp; //Makes temp the current head.
        }
        else {
            current = system->modules[index];
            while (current->next && system->compare(temp, current->next) > 0) { //While current isn't the last node in the LinkedList and temp comes after the node after current
                current = current->next;
             }
            temp->next = current->next; //Adds temp in between current and current->next.
            current->next = temp;
        }
    }
    return 1;
}

以上所有操作都按预期工作,除了打印system 的内容时,控制台指示存在内存泄漏,我假设是因为根据 valgrind 告诉我的信息,我未能正确释放temp。我的问题是不知道在哪里释放它——似乎我把它放在任何地方都会在打印内容后导致段错误。根据我的理解,我必须确保没有其他变量取决于temp 所持有的值,但考虑到我的 if 语句的每个可能结尾都导致分配@,我似乎无法找到一种方法来做到这一点987654333@ 到modules 内的一个节点。将free(temp) 放在逻辑和return 1 之间也会产生段错误,我假设是因为我经常在连续多次调用addMod 时再次malloc temp

总而言之,要向可能填充或不填充的 LinkedList 添加一个新节点,其中这个新节点可以插入到 LinkedList 中的任意位置,我必须将内存分配给一个临时节点,以便我以后可以插入。成功插入节点后,在哪里释放分配的内存?

【问题讨论】:

  • 添加到链表时,没有“临时”节点。只有“添加”节点,而这正是您在这里所拥有的。每当需要清理和/或以其他方式管理对象时,您都应该释放“系统”(无论是什么)实例中的 所有 节点。也就是说,如果你真的感兴趣的话,这可以在大约 1/5 的代码中完成,并且仅供参考,if ([any of the constructors are invalid]) return 0; 应该在 before malloc 之前完成。如果这样做了它所声称的(仅返回 0),那肯定是一个泄漏。
  • 可以有根据程序逻辑删除系统模块的功能,可以释放模块。仅仅免费是不够的,但 Modules->text 也必须被释放。如果免费导致段错误,则可能 temp 正在实际代码中重新分配垃圾或未分配地址,可以在实际代码中或使用 gdb 进行跟踪。
  • @WhozCraig 您的第一句话实际上非常有帮助。我想我认为 temp 是在我将它的“副本”放入链表之后需要摆脱的东西,我现在看到的并不是它的工作原理。我重写了一个单独的函数,该函数应该清除所有内容以遍历每个链表的每个成员并释放节点本身后面的文本字段,并且我已经修复了内存泄漏。感谢您的帮助。
  • @user11500789 你是不是有点好奇如何让插入功能更简单
  • @WhozCraig 是的,请

标签: c struct linked-list malloc free


【解决方案1】:

假设您对System 实例的管理是合理的(一个很大的假设,因为我看不到该代码),您在temp 的内存分配中存在巨大的漏洞,随后的硬return 0 在条件下“构造函数”检查失败。更重要的是:

Module *temp = malloc(sizeof(Module)); // memory allocated here...
Module *current;
temp->next = NULL;

if ([any of the constructors are invalid]) 
    return 0; // and leaked here.

这可能就像交换支票一样简单。显然,应该考虑和评估其他应该释放动态分配的代码。


更简单的方法

节点添加代码是复杂的,它不需要。最后,您真正应该关心的是找到新节点所在的位置。

  1. 如果表中的槽为空,则它是该列表中的第一个节点。
  2. 如果表中的槽不为空,则找到已排序的位置并将其插入其中。

这两者都可以通过使用指向指针的单个while循环来完成,其中所述实体保存将在中保存新节点的指针的地址 以上任何一种情况,作为奖励,手术插入实际上是两个任务。

这样做是这样的。请注意,大部分代码只是使Module 对象安全。实际插入只是一个while循环和一些指针分配。它假定System 中的表最初包含 NULL 条目:

int addMod(System *system, const char *text, int num1, int num2, int index)
{
    // allocate new node here
    Module *temp = malloc(sizeof *temp);
    if (temp == NULL)
    {
        perror("Failed to allocate new Module");
        return 0;
    }


    size_t len = strlen(text);
    temp->text = malloc(len + 1);
    if (temp->text == NULL)
    {
        perror("Failed to allocate module name");
        free(temp);
        return 0;
    }

    // finish copying member data
    memcpy(temp->text, text, len);
    temp->text[len] = 0;
    temp->num1 = num1;
    temp->num2 = num2;

    // now find where it belongs, and set next appropriately    
    Module **pp = system->modules + index;
    while (*pp && system->compare(temp, *pp) <= 0)
        pp = &(*pp)->next;

    temp->next = *pp;
    *pp = temp;
    return 1;
}

了解这是从我认为你的System 类型的样子得到的,因为它从未出现过:

typedef struct System
{
    Module *modules[MAX_MODULES];
    int (*compare)(const Module* lhs, const Module *rhs);

} System;

我相当有信心它与此类似。当然,如果不是,您将不得不适应。我建议您查看此内容并在调试器中逐步完成。现场观看是无可替代的。

祝你好运。

【讨论】:

  • int addMod() 需要一个最终的return
猜你喜欢
  • 2020-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
  • 2013-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多