链表节点内存释放后,为何仍能访问到val值?
链表内存释放后的指针访问疑问
假设有链表:[1] -> [2] -> [3] -> [4],节点结构体定义如下:
typedef struct Node { int val; struct Node* next; }Node;
持有链表的head指针,执行以下内存释放操作:
printf("%i", head->val); // 输出1 Node* tmp = head; while(tmp != NULL) { Node* tmp2 = tmp; tmp = tmp->next; free(tmp2); } printf("%i", head->val); // 输出一个大数,但不为NULL if (tmp == NULL) { print("is null"); // 此语句会执行 }
疑问
为何head->val仍可访问且不为NULL,而tmp为NULL?释放内存后head->val不该变为NULL吗?既然head是指针,指向的地址已被free,为何还能访问到值?
解答
free()的本质是把内存归还给操作系统,它不会修改指针本身的值,也不会主动清空内存里的原有数据。head指针依然保存着原来的内存地址,只是这块地址现在已经不属于你的程序了。- 访问已被
free的内存属于未定义行为:操作系统可能暂时还没覆盖这块内存的内容,你就可能读到旧值;也可能已经把这块内存分配给其他程序/数据,你读到的就是垃圾值(比如代码里的那个大数)。运气差的话,甚至会直接触发程序崩溃——这些情况都没有固定规律,完全取决于系统的内存管理机制。 tmp最终是NULL和free无关:循环里每次都会先把tmp更新为tmp->next,再释放当前节点。当遍历到最后一个节点(值为4的节点)时,tmp会被更新为它的next(也就是NULL),然后释放最后一个节点,循环结束后tmp自然就是NULL。- 别混淆类型:
head->val是int类型,而NULL是指针类型的空值标记,两者完全不是一个类型,int变量不可能变成NULL。你可能把“指针本身被置空”和“指针指向的内容”搞混了——free既不会把head置为NULL,也不会修改它指向的val的值(只是这块内存不再属于你了)。
内容的提问来源于stack exchange,提问作者Sombre Dreamer
相关产品推荐
相关产品推荐

