2013-07-29 53 views
10

我读理查德·里斯的新的(2013年5月)O'Reilly出版的“了解和使用C指针,指向”,我有一个关于一些代码其中的问题,第85页上realloc后使用原始指针?

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()的理解是,当新分配成功时,最初分配的内存被释放。如果这是正确的,那么有问题的线路正在使用悬挂指针,无辜?该表达式的RHS上的buffercurrentPosition都是指向已被释放的内存的指针。

我的直觉是重写这个,以避免使用悬挂指针通过使用length,毕竟它已经在附近。我想,以取代最后两行:

buffer = newBuffer; 
currentPosition = buffer + length; 

然而,想必代码写的作品,因为这两个指针仍持有地址(尽管垃圾),以及这两个地址之间的偏移仍然可以被计算为一种重新分配的方式currentPosition。那么,我是否只是在对此感到不安呢?

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

+0

在重新分配时,“length”大于缓冲区的大小(调整前的maximumLength)。如果我正确解释意义,你应该使用'currentPosition = buffer + length - 1'。 – Casey

+0

实际上,我在发布问题之前检查过。该书的代码将“length”和“currentPosition”初始化为零。 'length'在第一个条件中增加,所以它总是超过最后一个添加的元素的索引。 'currentPosition'是新元素被添加的地方,并且在添加之后得到递增。这不是我如何编写代码开始的,但是按照给定的代码,'buffer + length'是正确的。 – verbose

+0

所以'currentPosition'是一个预先组成的'buffer + length'?我立场纠正(并且被冗余略微困惑)。 – Casey

回答

9

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

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

+0

来源?我没有预料到这一点。 –

+2

@CoryNelson C11,6.5.6p8指针算术。如果结果不在数组对象中或者超过最后一个元素=>未定义的行为。 – ouah

+1

@Ouah,我认为这是指您尝试解除结果的引用。 – ROTOGG

0

只要您不尝试解除引用指针(即应用操作符*),则使用悬挂指针(例如“指针算术”)是安全的。

+3

这是错误的,因为C标准不能保证以前指针对不再存在的对象的算术有效。你可能会认为指针是作为内存地址来实现的,算术地址显然起作用,但指针不一定以这种方式实现。此外,允许优化器根据C的规则进行扣减,这可能导致令人惊讶的行为。 –