”悬空指针“的怪异现象!!

看起来有问题,但是运行起来却没有问题,

/*我的代码*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    char *p = NULL;
    p = ( char * )malloc( 4 * sizeof( char ) );
    free( p ); /****这里已经释放了p指向的内存块****/
    strcpy( p, "abc" );
    printf( "%s\n", p );
    retrun 0;
} 
/*free( p )释放了p指向的内存块,但是并没有改变p本身。于是产生了悬空指针,此时
p不再指向有效的内存块,strcpy函数修改了p指向的内存块,却没有造成程序崩溃,为啥?       ****不科学啊?*/
本人再Mac OS X 10.9上编译,运行却没有出错。求解释》》》!!!
阅读 7.7k
10 个回答
char *p = NULL;    // 声明p 并赋值NULL
p = ( char * )malloc( 4 * sizeof( char ) );   // p的值现在是一个内存地址
free( p );  // p的值所表示的那块内存被释放
            // 释放的意思是标记为空闲,可利用的,下次再malloc的时候可以用这块内存
            // 但是p现在的值,根!本!没!变!还是原来那个内存地址
strcpy( p, "abc" ); // 把"abc" 拷贝到p指向的区域,p还指着那块内存
                    // 只要这块内存没被再次分配,万事大吉~
                    // 如果别的程序正在用这块内存,或者你的程序其他地方用到了这块内存
                    // (你不是释放了嘛,操作系统当然可以重新分配)
                    // 恭喜你,要出问题了,出啥问题?我也不知道。。。取决于程序是怎么用这块内存的 
         // 要我举例? 好吧,比如浏览器用包含这4个字节的一块内存区域存放一张图片
         // 那么图片中这几个字节就被你改写了,图片可能就花了。或者显示不出来了。。

通俗点说,你吃完了雪糕把木棍扔在垃圾桶里,往前走了两步突然灵光一现,又回去垃圾桶把木棍捡出来舔一下。
你看,只要你动作够快,在垃圾车收垃圾之前是能在垃圾桶里找回来那根木棍的

但显然的使用free掉的内存和舔垃圾桶里捡来的木棍一样脑残,说不定你就捡到别人扔的木棍了

我觉得楼上诸位没有说到点子上 :)

这里虽然调用了free(), 但是这段内存一般不会立刻直接 交还给 OS, 所以不会有 segmentation fault.

malloc/free 都是库函数, 一般去调用 类似 sbrk之类的系统调用去 "增加/减少 程序可用的堆区的空间". 但是 free之后, 可能只是把 这段内存 放入 free list中, 这段内存还在 "程序可用的堆区的空间". 所以不会sf.

这是野指针啊。Linux也能运行,运行没错不代表程序没问题。

分配的内存就像一间一间的房子;
free指令就是在这间房子上写上“拆”--->但不是马上就拆(回收),OS会自动处理的。
只要写着“拆”的房屋没被系统回收,当然是可以住人的。---->(即编译也可以运行)
如果os已经回收了你还去住或你正住着os回收了,那就-->"segmentation fault"

c语言就是这么弄得,但是它相信程序员free后就不会再去调用了,这样做语义上说不通,而且会有未定义的危险,所以可以在free后加上p = NULL

我们一般叫野指针非法写
举个例子,假设你的房子被政府征收,之后装修公司不知情又按照老地址去装修了一下。如果房子尚未分配给下家,那还好未被发现。如果已经有下家入住,就会出事。

商业代码一般都是:

#define FREE(p) /
{ /
free(p); /
p = NULL; /
}

只要你搬走,指向你的地址立刻清空。

进程有自己的内存空间, 整个内存空间是由一个个 页面 组成的, 每个页面只有映射到物理内存, 才能使用, 否则 segment fault
用 malloc 分配的内存时, 会使用已有的页面, 或映射新的页面. free 释放内存时, 可能取消页面映射, 也可能不取消(页面其他部分还在使用).
free 之后, 如果取消了页面映射, 试用野指针就会 segment fault. 如果没有取消页面映射, 不会报错

free()只是把那段内存空间标记成了未分配,其内容不会被修改。

在实际应用程序中,会导致没法预料的行为,可能修改了其它模块的内存数据(该模块刚好申请了这块内存),也可能由于该内存所在的Page被取消引用了,导致segment fault.

根据不同的操作系统 不同的malloc free实现 这些行为都是不一样的 有些malloc库free之后会在内存里放个标记位 再次访问就可能会出现seg fault之类的错误 总之这类问题最好的做法就是free之后 把指针清零

IMHO,你对p分配了动态内存后又释放掉,所以原程序相当于

char *p = NULL;
strcpy( p, "abc" );
printf( "%s\n", p );

似乎没什么悬空指针的问题.如果是你说的悬空指针,我觉得应该是这样的:

char *p = NULL;
printf( "%s\n", p );
推荐问题
宣传栏