是否在C中获取无效指针的值未定义或实现定义的行为?

时间:2015-11-07 16:13:52

标签: c pointers undefined-behavior invalid-pointer

获取无效指针的值是根据this在C ++中实现定义的行为。现在考虑以下C程序:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int* p=(int*)malloc(sizeof(int));
    *p=3;
    printf("%d\n",*p);
    printf("%p\n",(void*)p);
    free(p);
    printf("%p\n",(void*)p); // Is this undefined or implementation defined in behaviour C? 
}

但是C中的行为是否相同?上述C程序的行为是否未定义或实现定义? C99 / C11标准对此有何看法? 如果C99&amp; C中的行为不同,请告诉我。 C11。

4 个答案:

答案 0 :(得分:7)

扩展Andrew Henle的回答:

来自C99标准,6.2.4:

  

对象具有确定其生命周期的存储持续时间。有三个存储持续时间:静态,自动和已分配。已分配的存储在 7.20.3中描述。 [...]指针的值变为不确定< / strong>当它指向(或刚刚过去)的对象到达其生命周期的末尾时。

然后在7.20.3.2中:标准继续描述malloc()calloc()free(),并提及

  

free函数会导致ptr指向的空格被释放。

在3.17.2中:

  

不确定价值

     

未指定的值或陷阱表示

在6.2.6.1.5中:

  

某些对象表示不需要表示对象类型的值。 如果对象的存储值具有这样的表示并且由不具有字符类型的左值表达式读取,则行为未定义。 [...]这样的表示称为陷阱表示。

由于指针变得不确定,并且不确定值可以是陷阱表示,并且您有一个左值变量,并且未定义读取左值陷阱表示,因此是,行为可能未定义。

答案 1 :(得分:4)

根据C standard, section 6.2.4

  

对象的生命周期是程序执行期间的一部分   保证保留哪个存储空间。存在一个对象,   具有恒定的地址,并始终保留其最后存储的值   它的一生。如果一个对象在其生命周期之外被引用,   行为未定义。 指针的值变为   当它指向(或刚刚过去)的对象到达时不确定   生命周期结束

答案 2 :(得分:0)

如果编译器正确地确定代码将不可避免地获取a 指向已传递给“free”或“realloc”的对象的指针,即使 代码将不会使用由此标识的对象,标准将 在此之后对编译器可能做或不做的事情没有要求。

因此,使用如下构造:

char *thing = malloc(1000);
int new_size = getData(thing, ...whatever); // Returns needed size
char *new_thing = realloc(thing, new_size);
if (!new_thing)
  critical_error("Shrinking allocation failed!");
if (new_thing != thing)
  adjust_pointers(thing, new_thing);
thing = new_thing;
在大多数实现中,

可能允许代码节省重新计算的工作量 使用realloc缩小已分配块的事件中的一些指针 不会导致块移动,但没有什么不合法的 无条件报告缩减分配的实施 失败,因为如果它没有失败代码将不可避免地尝试比较 涉及指向realloc'ed块的指针。就此而言,它也会 对于实现来说,同样合适(虽然不那么“有效”) 保持检查realloc是否返回null,但允许任意代码 如果不执行则执行。

就个人而言,我发现通过阻止程序员在可以跳过某些步骤时确定测试的结果很少。如果指针没有改变,则跳过不必要的代码可能会在使用realloc缩小内存块的情况下显着提高效率(允许这样的动作移动块,但在大多数实现中它通常不会),但它是目前,编译器很有可能应用他们自己的积极优化,这将破坏试图使用这些技术的代码。

答案 3 :(得分:-2)

继续发表评论。我认为关于它是有效还是无效的混淆围绕着指针的哪个方面被问到。上面,free(p);将起始地址影响到p指向的内存块,它不会影响p本身的地址,它仍然有效。 p不再存在地址(因为它的价值),在重新分配之前不会留下不确定的地址。一个简短的例子有助于:

#include <stdio.h>
#include <stdlib.h>

int main (void) {

    int *p = NULL;

    printf ("\n the address of 'p' (&p) : %p\n", &p);

    p = malloc (sizeof *p);
    if (!p) return 1;

    *p = 3;

    printf (" the address of 'p' (&p) : %p   p points to %p   with value  %d\n",
            &p, p, *p);

    free (p);

    /* 'address of p' unchanged, p itself indeterminate until reassigned */
    printf (" the address of 'p' (&p) : %p\n\n", &p);

    p = NULL;  /* p no longer indeterminate and can be allocated again */

    return 0;
}

<强>输出

$ ./bin/pointer_addr

 the address of 'p' (&p) : 0x7fff79e2e8a0
 the address of 'p' (&p) : 0x7fff79e2e8a0   p points to 0x12be010   with value  3
 the address of 'p' (&p) : 0x7fff79e2e8a0

pmalloc的地址free本身未更改。受影响的是p的值(或更确切地说,地址p存储为其值)。在free后,地址p商店将发布到系统,无法再通过p访问。明确重新分配后p = NULL; p不再是不确定的,可以再次用于分配。)