【问题标题】:Using original pointer after realloc?在重新分配之后使用原始指针?
【发布时间】:2013-07-28 16:26:01
【问题描述】:

我正在阅读 Richard Reese 的新书(2013 年 5 月)O'Reilly 的新书“理解和使用 C 指针”,我对其中的一些代码有疑问,第 87 页。

if (++length > maximumLength) {
    char *newBuffer = realloc (buffer, maximumLength += sizeIncrement);

    if (newBuffer == NULL) {
        free (buffer);
        return NULL;
    }

    currentPosition = newBuffer + (currentPosition - buffer);
    buffer = newBuffer;
}

我希望变量的名称是不言自明的;如果需要上下文,我将进行编辑以提供整个代码块,而不仅仅是这段摘录。

我的问题是关于currentPosition = newBuffer + (currentPosition - buffer); 这一行。我对realloc()的理解是,当新分配成功后,原来分配的内存就被释放了。如果这是正确的,那么有问题的行是使用悬空指针,init?该表达式的 RHS 上的 buffercurrentPosition 都是指向已释放内存的指针。

我的直觉是重写它以避免使用length 来避免使用悬空指针,毕竟它已经存在了。我想将最后两行替换为:

buffer = newBuffer;
currentPosition = buffer + length;

但是,可能编写的代码可以工作,因为这两个指针仍然保存地址(尽管是垃圾),并且这两个地址之间的偏移量仍然可以作为重新分配 currentPosition 的一种方式来计算。所以我对此感到不安只是小气吗?

概括一下这个问题:一旦指针悬空,是否可以安全地将指针中包含的地址用于任何目的,例如计算偏移量?谢谢。

【问题讨论】:

  • 在重新分配时,length 比缓冲区的大小(调整前的maximumLength)大一。如果我正确解释了含义,您应该使用currentPosition = buffer + length - 1
  • 实际上,我在发布问题之前检查了这一点。本书的代码将lengthcurrentPosition 都初始化为零。 length 在第一个条件中递增,因此它总是超过最后添加元素的索引。 currentPosition 是要添加新元素的位置,并在添加后递增。这不是我开始编写代码的方式,而是按照给定的代码,buffer + length 是正确的。
  • 所以currentPosition 是预先组合的buffer + length?我站得更正了(对冗余有点困惑)。
  • 呃。丑陋的代码。也许至少添加一个 else ?我的批评是针对 R. Reese,而不是 OP。
  • @Jim,是的,可悲的是,它完全代表了本书的其余部分。

标签: c pointers realloc


【解决方案1】:

只要您不尝试取消引用指针(即应用运算符 *),使用悬空指针(例如“指针算术”)是安全的。

【讨论】:

  • 这是错误的,因为 C 标准不保证对不再存在的对象的先前指针进行算术运算。您可能会认为指针被实现为内存地址,并且地址上的算术显然有效,但指针不一定以这种方式实现。此外,允许优化器根据 C 的规则进行推论,这可能会导致令人惊讶的行为。
【解决方案2】:

一旦指针悬空,是否可以安全地将指针中包含的地址用于任何目的,例如计算偏移量?

不,这不安全。在free 之后,指针值是无效地址,如果不调用未定义的行为,则无效地址不能用于指针运算。

【讨论】:

  • @CoryNelson C11,6.5.6p8 指针算法。如果结果不在数组对象中或最后一个元素之后 => 未定义的行为。
  • @Ouah,我认为这是指您尝试取消引用结果时。
  • @ouah 本节适用于“当将具有整数类型的表达式添加到指针或从指针中减去时”——在他的示例中,他减去了两个指针。
  • 引用 6.2.4p2 会有所帮助:“当指针指向(或刚刚过去)的对象达到其生命周期的终点时,指针的值变得不确定。”
  • 感谢@ouah 指向标准的指针(har har)。我查看了 6.5.6p9,它明确表示“当减去两个指针时,两者都应指向同一个数组对象的元素,或者指向数组对象最后一个元素的元素。”所以由于这些指针没有指向任何地方,你是对的,这是未定义的行为。它可能适用于大多数实现,但它是非标准的,因此(我怀疑)是不可取的。
猜你喜欢
  • 2021-12-11
  • 2022-01-21
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-07
  • 2015-07-14
相关资源
最近更新 更多