释放指针后再对其进行赋值

5

我正在查看书籍“编程面试揭秘”中的以下代码:

bool deleteStack( Element **stack ){
      Element *next;
      while( *stack ){
            next = (*stack)->next;
            free( *stack );
            *stack = next;
      }
      return true;
}

我对C++或C不是很熟悉,所以这可能是一个愚蠢的问题,但是,在释放指针之后将某些东西分配给它会导致问题吗?


没有问题,就像@simonc所说的那样。你没有释放*stack的内容,而是释放了*stack指向的内存的内容。你的LOCs,对于常规变量来说,并没有更多的错误,就像这样做一样:a=1; a=0; /将其视为a的free()/ a=2; - user1284631
如果我在C++面试中被问到这个问题,我会说:“为什么不用智能指针呢?” - PinkElephantsOnParade
你不释放指针本身,而是释放指针所指向的内存空间。 - Martin York
@PinkElephantsOnParade:如果你正在实现一个容器(比如列表),通常不会使用智能指针,因为所有权语义通常在容器内部是明确定义和自包含的。自动化内存管理容器和智能指针有两种基本形式。 - Martin York
@LokiAstari 好的,没必要在不必要的时候动用大炮。 - PinkElephantsOnParade
4个回答

8
在您的例子中,*stack是一个指针。可以完全安全地释放其所指向的内存,然后将指针分配给一个新变量。
唯一不安全的事情就是在释放后对*stack进行间接引用。
free( *stack );
next = (*stack)->next;

*stack 指向的内存在 free 调用后具有不可预测的内容(甚至可能不再对您的进程可访问),因此这么做是错误的。


4
不,没事。你实际上并没有通过这种方式“释放指针”:
 free( *stack );

但是,你需要释放指向指针*stack的一些动态分配的内存。当你执行以下操作时:
*stack = next;

你只需要将指针指向不同的内存块即可,这就是全部。

1

这样做是安全的。当你看到像(*stack)这样的东西时,你可以把它想象成“由stack指向的”。由于free期望一个指向内存位置的指针,所以你正在释放进程虚拟内存中由stack指向的“内存槽”。 这意味着内存地址(即指针)的空间仍然可用,你可以重新使用它。
此外,我认为这可能很有用,当你使用箭头符号->时,你在C/C++中使用了两种不同的符号简化了它们的常见用法。因此,这个:stack->next与这个相同:(*stack).next 祝你好运。


2
这个:stack->next 和这个:(*stack).next 是一样的。OP实际上使用的符号是(*stack)->next,因为stack是指向元素的指针的指针,所以在使用->运算符之前必须进行解引用。 - Mike
是的,我知道。我只是在解释可能是他的问题。一开始并不容易读懂指针,所以我认为完全理解箭头符号可能会有用。但还是谢谢。 - Afonso Tsukamoto

1

在释放指针变量后将其赋值为NULL只是为了在代码中保留提示,以便识别是否对已释放地址进行了解引用。

如果我们不将已释放指针赋值为NULL,则行为未定义(50%的崩溃几率和剩余的堆损坏几率),如果我们对该已释放指针变量进行解引用。但是如果它被设置为NULL,它肯定会崩溃。如果堆被破坏,将很难识别错误而不是在一个地方崩溃。

请不要认为已释放的指针永远不会在您的代码中被解引用。如果项目长时间维护,则有添加(或修改)代码错误的机会。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接