【问题标题】:C implementation of a linked list remove element function链表删除元素功能的C实现
【发布时间】:2017-10-06 19:35:43
【问题描述】:

我正在阅读一本教科书,遇到了以下从链表中删除元素的函数。 CELL 类型定义如下;

typedef struct CELL CELL;
struct CELL {
    int element;
    CELL* next;
};

void delete(int x, CELL** pL) {
    if ((*pL) != NULL) {
        if (x == (*pL)->element)
            (*pL) = (*pL)->next;
        else
            delete(x, &((*pL)->next));
    }
}

现在假设我有一个从 5 开始的包含以下元素的链表;

5->10->3->21->15->7

现在假设我删除元素 10。我的问题是当 delete 函数返回时包含 10 的 CELL 会发生什么,因为这个 CELL 没有被引用?不是还在占内存吗?

【问题讨论】:

  • 通过代码获取调试器步骤,并检查变量。
  • 无关,该功能是原则的典范:“仅仅因为你可以并不意味着你应该。”该算法很容易移植到迭代解决方案。可能用作数据结构课程/课程的递归解决方案的一部分,它可能在那里达到其目的,但在实践中避免它。
  • 是的,它仍然在占用空间,虽然不清楚元素是如何分配的。最好让delete 函数与内存管理无关,并返回指向已删除的CELL 的指针(如果没有删除单元格,则返回NULL)并让调用者释放它。你可以有一个包装函数来释放元素。这个函数的另一个奇怪之处是使用尾递归而不是迭代。如果编译器没有对其进行优化,如果列表很长,您可能会出现堆栈溢出。

标签: c pointers memory linked-list


【解决方案1】:

当删除函数返回时,包含 10 的 CELL 会发生什么,因为这个 CELL 未被引用?不是还在占内存吗?

绝对!一旦函数返回,包含 10 的CELL 就会成为内存泄漏,除非有另一个指针引用它,或者CELL没有动态分配的。

如果用于操作列表的其他函数(创建、插入等)的实现方式假定列表对其单元格的所有权,请在重新指向 *pl 的分支中添加对 free 的调用到(*pL)->next。做一个临时变量,把*pl的地址存进去,重新指向,在临时变量上调用free

【讨论】:

  • 谢谢。在您发布之前,我考虑过删除内部ifelse 之间的语句,并按顺序添加以下三个语句; int* temp = (*pL)->next;free(*pL);*pL = temp; 现在我想知道,这会实现同样的效果,还是按照您所说的方式做会更好?
  • @BlaqICE 是的,它会完成同样的事情:无论您是使用temp 来表示要删除的节点还是要保留的节点,都可以方法会产生相同的结果。
【解决方案2】:

由于您没有释放代码中的任何内存,它应该仍然存在于某处。您只需从链接列表中取消链接该元素。

根据您管理这些元素的内存的方式,这可能是也可能不是问题(内存泄漏)。例如,如果每个元素都是使用malloc 分配的,并且链表只有指向该元素的指针,那么您很可能发生了内存泄漏(并且需要使用free)。但是如果节点被分配在堆栈上(例如使用alloca)或在稍后释放的某个内存池中,那么可能不会有泄漏。所以这真的取决于你如何处理内存以及何时释放它。

【讨论】:

  • 啊,是的,我已经习惯了用户定义类型的变量在 Java 中是堆动态的,以至于我忘记了它们在 C 中也可以是堆栈动态的。谢谢。
【解决方案3】:

对于初学者来说,关于函数本身的一些评论。最好按以下方式声明函数

int delete( CELL **pL, int x );

事实上,这个函数做了两件事。它搜索值等于 x 的节点。如果找到这样的节点,它会取消链接。

因此希望该函数报告是否找到了这样的节点。

另一种声明函数的方式是在函数没有释放注释中 @IanAbbott 指向的已移除节点时声明函数是

CELL * delete( CELL **pL, int x );

即函数返回指向已删除节点的指针,如果没有找到值等于 x 的此类节点,则返回 NULL。

其次,最好将第一个参数声明为对节点的引用,将第二个参数声明为搜索值。这首先是您要处理的内容,然后是您处理列表的方式。

至于你的问题,那么我已经说过的功能会取消链接节点。节点本身不会从内存中删除,也不会更改。如果它是动态分配的,那么您必须保留指向该节点的指针的副本。否则会出现内存泄漏,因为如果没有指向节点的指针,您将无法释放它。

【讨论】:

  • 您可以返回指向已删除节点的指针,而不是 int。如果没有找到返回NULL。然后调用者可以做任何需要做的事情来释放节点。
  • @IanAbbott 是的,这是一种替代方法。
猜你喜欢
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 2020-03-16
  • 1970-01-01
  • 2020-09-04
  • 2021-03-26
  • 2018-08-30
  • 2018-07-14
相关资源
最近更新 更多