C 语言:释放动态分配的内存,为何还能访问?

2017-06-23 17:06:21 +08:00
 NullMan
#include <stdio.h>
#include <stdlib.h>

#define N 50

int main(void) {
    int *pi;
    pi = (int *)malloc(N * sizeof(int));
    if (pi == NULL) {
        printf("Out of memory!\n");
        exit(1);
    }
    for (int i = 0; i < N; i++) {
        *(pi + i) = 100;
    }
    free(pi);
    pi[10] = 200;
    printf("%d\n", pi[10]); // 输出 200
    return 0;
}

执行 free(pi) 了,没道理 pi 还能访问。我看了下 c 标准,发现有这么一句话:

The behavior is undefined if after free() returns, an access is made through the pointer ptr (unless another allocation function happened to result in a pointer value equal to ptr)

这到底释放了内存没有?我是这么猜想的,这块内存其实回归了内存池,如果有其他的内存分配,将有可能复用这free 过的内存块。先前代码输出的200, 其实等同于垃圾值,就像声明了一个int i但未初始化而直接访问i将会得到上次使用过i内存的垃圾值。

不知我理解是否正确?

编译器版本如下:

Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

本人初学 C,望指点!多谢多谢!

4833 次点击
所在节点    C
67 条回复
canfoderiskii
2017-06-23 17:09:50 +08:00
内存它就躺在那里,为什么不能访问?只是 free 之后再访问不和逻辑,也很危险。
deweixu
2017-06-23 17:10:17 +08:00
gongzhang
2017-06-23 17:10:25 +08:00
是哒 ( ̄∇ ̄)
macha
2017-06-23 17:10:48 +08:00
你的感觉是对的。
NullMan
2017-06-23 17:14:26 +08:00
我想了想,既然只是个标准,而且又没说明如何处理这个现象,那么编译器实现者爱咋呀就咋样,如果我是编译器实现者,我直接给退出程序也是正常。这么一想,我就释然了。
after1990s
2017-06-23 17:18:09 +08:00
@NullMan malloc 不是编译器实现的,是 c 语言库实现的。
Cooky
2017-06-23 17:19:00 +08:00
你可以试着往 free 掉的地方写数据看看
reus
2017-06-23 17:31:51 +08:00
free 只是告诉内存分配器这块可以用于分配,并不阻止你继续用。内存分配器也不知道你用不用,反正它允许用。
NullMan
2017-06-23 17:34:40 +08:00
@after1990s c 标准库也是代码,也是要编译的嘛。
jmp2x
2017-06-23 17:35:37 +08:00
catror
2017-06-23 17:47:41 +08:00
释放了请把指针置空,编程的好习惯
NullMan
2017-06-23 17:55:23 +08:00
@catror 卧槽!这个很赞!多谢!
Mirana
2017-06-23 18:14:19 +08:00
free 掉之后只是还给 memory allocator 了,不一定还给操作系统
kmyzzy
2017-06-23 18:17:49 +08:00
@catror 这可未必
cuteshell
2017-06-23 19:11:22 +08:00
free 了,指针还是原来的值,还是可以访问,free 是告诉操作系统这块内存我不用了,操作系统可以分配给其它的 malloc 申请,只不过释放了内存的指针是野指针。
shuax
2017-06-23 19:14:47 +08:00
就和你在硬盘上面删除一个文件一样的,你删一个 10g 的文件难道还要用 0 给你填充,浪费时间,声明这块空间可以用就行了。非 ssd
geelaw
2017-06-23 19:21:40 +08:00
@catror 这样做反而可能错失发现逻辑错误的机会。

这个行为是符合标准的,因为标准说未定义,你能用可以算是一种走运。
DustOnTheHeart
2017-06-23 19:46:28 +08:00
free 告诉系统这块内存我不用了,但是指针指向的内存地址没变,在这个程序执行的过程中也没有在此改变这个指针指向的内存中的值,所以再次使用这个地址的内存的时候仍然得到的是上个值
lrxiao
2017-06-23 20:15:13 +08:00
undefined.....(
catror
2017-06-23 20:37:01 +08:00
@kmyzzy 举个例子来说?内存已经释放了这个指针没有意义了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/370623

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX