realloc后可以使用原始指针吗?

11

我在阅读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()的理解是,当新的分配成功时,最初分配的内存将被释放。如果这是正确的,那么这一行代码使用了悬空指针,对吗?在该表达式中,右侧的buffercurrentPosition都是指向已被释放的内存的指针。

我的直觉是通过使用length来重新编写代码以避免使用悬空指针。毕竟,length已经存在。我想用以下代码替换这些最后两行:

buffer = newBuffer;
currentPosition = buffer + length;

然而,假设代码能够正常工作是因为这两个指针仍然保留了地址(虽然可能是垃圾值),并且这两个地址之间的偏移量可以被用来重新分配 currentPosition。所以说,我对此感到不安是否只是过于挑剔?

一般化问题:一旦指针变成悬空状态,是否可以安全地将指针中包含的地址用于任何目的,例如计算偏移量?谢谢。


在重新分配内存时,length 的值比缓冲区大小(调整前的 maximumLength)大 1。如果我理解正确的话,你应该使用 currentPosition = buffer + length - 1 - Casey
我在发布问题之前就已经检查过了。该书的代码将lengthcurrentPosition都初始化为零。length在第一个条件语句中递增,因此它始终比最后添加的元素的索引多一。currentPosition是新元素要添加的位置,在添加后会递增。这不是我一开始编写代码的方式,但是考虑到给定的代码,buffer + length是正确的。 - verbose
所以 currentPosition 是一个预组合的 buffer + length?我纠正了(并且对冗余感到有些困惑)。 - Casey
呃,这代码太丑了。至少加个else语句吧?我的批评是针对R. Reese而不是OP的。 - Jiminion
@Jim,是的,不幸的是,这相当代表了整本书的水平。 - verbose
2个回答

10

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

不安全。在释放指针后,指针值是一个无效地址,而无效地址不能用于指针算术运算,否则会导致未定义行为。


2
@CoryNelson C11,6.5.6p8指针算术。如果结果不在数组对象或超过最后一个元素,则为未定义行为。 - ouah
1
@Ouah,我认为这是指当您尝试取消引用结果时。 - ROTOGG
3
这一部分适用于“指针被加上或减去整数类型的表达式”的情况 -- 在他的例子中,他正在减去两个指针。 - Cory Nelson
6
请引用6.2.4p2:“当指向的对象(或紧挨着的下一个对象)生命周期结束时,指针的值将变得不确定。” - Casey
4
谢谢你提供的指针(哈哈),@ouah. 我查了一下6.5.6p9,它明确表示:“当两个指针相减时,两个指针都必须指向同一个数组对象的元素或指向数组对象的最后一个元素之一。”因此,由于这些指针没有指向任何地方,你是正确的,这是未定义行为。虽然这可能在大多数实现中都有效,但它是非标准的,因此(正如我所怀疑的)不建议使用。 - verbose
显示剩余5条评论

0

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


5
这是错误的,因为C标准没有保证在已经不存在的对象的原指针上进行算术运算是有效的。你可能会认为指针是作为内存地址实现的,而地址的算术运算显然有效,但指针不一定是这样实现的。此外,优化器可以根据C规则进行推断,这可能导致出人意料的行为。 - Eric Postpischil

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