我们可以访问已释放的内存吗?

Ash*_*wal 0 c segmentation-fault

我注意到函数的局部变量一直在获得相同的内存,因此我尝试在从函数返回后访问内存。 (我试图访问解除分配的内存)

第一次尝试: 在第一个代码中,我返回了局部变量的地址(也收到了编译器的警告),然后当我尝试在 main 中访问此内存时,程序由于分段错误而停止。

#include<stdio.h>
int * fun()
{
    int a;
    printf("Address of a is %p\n",&a);
    printf("Value of a is %d\n",a);
    return &a;
}
int main()
{
    int *p;
    p=fun();
    *p=100;//Segmentation fault: program stops execution at this line 
           // which can be verified as the printf statement in next line doesn't execute
    printf("Hi");
    fun();
}
Run Code Online (Sandbox Code Playgroud)

输出: testC.c:26:12: 警告:函数返回局部变量的地址 [-Wreturn-local-addr] return &a; ^~

a 的地址是 000000000061FDDC

a 的值为 0

第二次尝试: 现在我尝试了同样的事情,但有一点变化,我没有直接返回地址,而是在额外指针的帮助下返回了它,在这种情况下,我没有收到编译器的任何警告,我成功地访问了一个已释放的内存main 通过将值 100 放在该地址处,该地址可以在下一次函数调用期间看到。

#include<stdio.h>
int * fun()
{
    int a,*p;
    printf("Address of a is %p \nAddress of p is %p\n",&a,&p);
    printf("Value of a is %d\n",a);
    p=&a;
    return p;
}
int main()
{
    int *p;
    p=fun();
    *p=100;//Segmentation fault: program doesn't stop here
           //compiler is not able to catch this fault and we access a deallocated memory
           //and successfully insert 100 at a deallocated memory, which we can see in next fun() call.
    fun();
}
Run Code Online (Sandbox Code Playgroud)

输出:

a 的地址是 000000000061FDDC

p 的地址是 000000000061FDD0

a 的值为 0

a 的地址是 000000000061FDDC

p 的地址是 000000000061FDD0

a 的值为 100

有人可以解释一下如何访问这样的释放内存吗?

pax*_*blo 6

有时,未定义的行为会像您期望的那样工作 - 毕竟,这是它可以做的无数事情之一,也是它最阴险的功能 - 从程序员的角度来看,如果每次都崩溃并带有信息性消息会更好(然而,这几乎肯定会减慢 C 的速度,以至于人们会大声疾呼旧行为)。

没有办法做事实上,它可以工作使它成为一个好主意,因为它也可能会做的一个其他的极大数减一的东西,比如形成一个微型黑洞,其吞下一半的房子蒸发,或擦除存储设备之前,播放文件时derisive_laughter.mp3:-)

详细信息可以在(对于 C11)中找到6.2.4 Storage durations of objects

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

a根据同一部分,您的变量是自动变量:

其标识符声明为没有链接且没有存储类说明符 static 的对象具有自动存储持续时间

对于这样一个没有可变长度数组类型的对象,它的生命周期从进入与其关联的块直到该块的执行以任何方式结束。

由于该a变量的生命周期在 结束时终止fun(),指向它的指针变得不确定,这包括在6.5.3.2 Address and indirection operators

如果为指针分配了无效值,则一元运算*符的行为未定义。

该部分引用了以下脚注:

一元运算*符取消引用指针的无效值包括空指针、与指向的对象类型不正确对齐的地址以及对象生命周期结束后的地址。