为何free()会影响list->next指针?链表内存疑问求助
链表内存管理问题解答
问题描述
在实现链表添加节点时遇到以下问题:将list->next指向指针n的地址后,调用free(n),再次打印第二个节点的int值时变为垃圾值。想搞清楚:
- 内存中
n和list->next是持有相同地址的独立指针还是同一指针? - 若为独立指针,为何
free(n)会影响list->next? free(n)后第二个节点已失效,为何仍能通过list->next->next添加第三个节点?
代码示例
#include <cs50.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <math.h> #include <stdlib.h> typedef struct node { int number; struct node *next; } node; int main(void) { node a; a.number = 1; a.next = NULL; node *list = NULL; list = &a; // 第一个节点 printf("%i\n", a.number); node *n = malloc(sizeof(node)); // 创建指向第二个节点的指针 if (n != NULL) { n->number = 2; n->next = NULL; } list->next = n; // 将节点加入链表 printf("%p\n%p\n", n, list->next); // 打印地址 printf("%i\n", list->next->number); free(n); printf("%p\n%p\n", n, list->next); // 再次打印地址 printf("%i\n", list->next->number); n = malloc(sizeof(node)); printf("%p\n%p\n", n, list->next); if (n != NULL) { n->number = 3; n->next = NULL; } list->next->next = n; printf("%i\n", (*(*(*list).next).next).number); return 0; }
输出结果
1 0x5562319d62a0 0x5562319d62a0 2 0x5562319d62a0 0x5562319d62a0 1445140950 0x5562319d62a0 0x5562319d62a0 3
问题解答
n和list->next是独立指针:它们是两个完全独立的指针变量——n是main函数的局部变量,list->next是结构体a的成员变量,各自占用不同的内存空间。只是它们存储的数值相同,都是指向同一块堆内存的地址,所以输出里两者的地址值完全一致。free(n)影响的是指针指向的内存,而非指针本身:free()函数的作用是释放指针指向的堆内存,不是销毁指针变量。当你调用free(n)后,n和list->next共同指向的那块内存被操作系统回收,标记为可复用区域,里面原来存储的2不再受保护,后续可能被其他数据覆盖,所以读取list->next->number会得到垃圾值。此时list->next这个指针变量本身的数值(地址)并没有改变,只是它指向的内存已经失效。通过
list->next->next添加节点属于未定义行为:free(n)后,list->next变成了野指针(指向已释放的内存),对野指针进行解引用(比如访问list->next->next)是C语言标准明确的未定义行为。这次运行看似成功,只是因为那块被释放的内存暂时还没被操作系统分配给其他操作,没有被覆盖,但这种行为完全不可靠,随时可能导致程序崩溃、数据损坏等问题,绝对不能在实际代码中这么写。
内容的提问来源于stack exchange,提问作者alksdhalksjdb
相关产品推荐
相关产品推荐

