为什么在释放指向它的指针后仍然可以访问结构的成员?

Duc*_*ain 7 c struct pointers memory-management

如果我定义一个结构......

struct LinkNode
{
  int node_val;
  struct LinkNode *next_node;
};
Run Code Online (Sandbox Code Playgroud)

然后创建一个指向它的指针......

struct LinkNode *mynode = malloc(sizeof(struct LinkNode));
Run Code Online (Sandbox Code Playgroud)

......然后终于免费()它......

free(mynode);
Run Code Online (Sandbox Code Playgroud)

...我仍然可以访问结构的'next_node'成员.

mynode->next_node
Run Code Online (Sandbox Code Playgroud)

我的问题是:底层机制的哪一部分跟踪这个内存块应该代表一个结构LinkNode的事实? 我是C的新手,我期望在我使用指向我的LinkNode的指针上的free()后,我将无法再访问该结构的成员.我期待某种"不再可用"的警告.

我想更多地了解基础流程的工作原理.

AnT*_*AnT 6

编译后的程序不再具有任何关于struct LinkedNode或字段命名的知识next_node,或类似的东西.任何名称都已从编译的程序中完全消失.编译程序根据数值运算,可以发挥内存地址,偏移量,索引等角色.

在你的例子中,当你读mynode->next_node入你的程序的源代码时,它被编译成机器代码,它只是从一些保留的内存位置(mynode在你的源代码中称为变量)中读取4字节的数值,加上4(这是next_node字段的偏移量)并在结果地址处读取4字节值(即mynode->next_node).如您所见,此代码按整数值(地址,大小和偏移量)运行.它不关心任何名称,如LinkedNodenext_node.它不关心是否分配和/或释放内存.它并不关心这些访问是否合法.

(我在上面的示例中重复使用的常量4特定于32位平台.在64位平台上,它将在大多数(或所有)实例中被8替换.)

如果尝试读取已释放的内存,则这些访问可能会使程序崩溃.或者他们可能不会.这是一个纯粹的运气问题.就语言而言,行为是不确定的.


Ant*_*ony 5

没有,你也不能。这是未定义行为的典型案例。

当你有未定义的行为时,任何事情都可能发生。它甚至可能看起来有效,但一年后却随机崩溃。


Mik*_*olf 5

它的工作纯属运气,因为释放的内存尚未被其他内容覆盖。一旦释放了内存,您就有责任避免再次使用它。