关于指针的free操作
最近刚学链表,在学到链表的销毁时,上网查了一些资料,都说要最后再销毁head,这点不太没明白,而且对于野指针我是这样觉得在链表中每一块内存之间都有联系,那我应该完全可以在...
最近刚学链表,在学到链表的销毁时,上网查了一些资料,都说要最后再销毁head,这点不太没明白,而且对于野指针我是这样觉得在链表中每一块内存之间都有联系,那我应该完全可以在将指针a free后继续使用a进行a=a->操作吧!我是觉得free只是给了一个可以利用的标记,如果明确这块内存存放的是啥的话,就可以继续使用。不知道想法对不对。
问题有两点:
1.删除链表的顺序,以及操作(能给出简单代码,表示万分感谢)不给也没事
2.确认想法的正确性。 展开
问题有两点:
1.删除链表的顺序,以及操作(能给出简单代码,表示万分感谢)不给也没事
2.确认想法的正确性。 展开
7个回答
展开全部
回答问题1:
删除全部链表结点释放内存时,如果是双向链表,从前到后,或从后到前都无所谓,都可以。如果是单向链表,只可以从前到后。说白了就是能遍历全部结点就行。
从前到后的代码如下:
p=head; //p开始指向首链
while(p)
{
tmp=p; //保存当前要释放的结点指针
p=p->next; //释放前,先得到下一个结点指针
free(tmp); //再释放即可
}
回答问题2:
内存释放不是像磁盘空间那样标记那么简单,而且某处内存一旦释放,很可能会被另外线程分配走,内容就不是以前内容。另外内存管理机制采用分页映射,比如你申请的内存地址是0x10000000处,实际这个地址并不是在物理内存的地址的0x10000000这个地方,它可能在物理内存的0x800000处,它们只是个映射关系。当你释放内存时,就解除了这种映射,当你再操作0x10000000内存时,就会发生异常,你根本就读不到任何数据。
现在的操作系统的内存机制都是采取虚拟分页映射,至于为什么,你可以查阅相关资料。
综上原因,所以不能释放了还用其内容,解决方法是把要用的东西保存到其它位置,再释放内存,再用保存的。如同上面的演示代码。
删除全部链表结点释放内存时,如果是双向链表,从前到后,或从后到前都无所谓,都可以。如果是单向链表,只可以从前到后。说白了就是能遍历全部结点就行。
从前到后的代码如下:
p=head; //p开始指向首链
while(p)
{
tmp=p; //保存当前要释放的结点指针
p=p->next; //释放前,先得到下一个结点指针
free(tmp); //再释放即可
}
回答问题2:
内存释放不是像磁盘空间那样标记那么简单,而且某处内存一旦释放,很可能会被另外线程分配走,内容就不是以前内容。另外内存管理机制采用分页映射,比如你申请的内存地址是0x10000000处,实际这个地址并不是在物理内存的地址的0x10000000这个地方,它可能在物理内存的0x800000处,它们只是个映射关系。当你释放内存时,就解除了这种映射,当你再操作0x10000000内存时,就会发生异常,你根本就读不到任何数据。
现在的操作系统的内存机制都是采取虚拟分页映射,至于为什么,你可以查阅相关资料。
综上原因,所以不能释放了还用其内容,解决方法是把要用的东西保存到其它位置,再释放内存,再用保存的。如同上面的演示代码。
展开全部
第一个问题,你是否将两个程序放在一起编译了,所以root就一直是第一个程序中定义的
第二个问题,free释放内存是成功了,但指针的值还是指向原来分配的地址空间,但这个地址已经是无效的,如果使用会发生内存错误。必须你自己赋值才能把它设成NULL,即:
root = NULL;
你free(root)后判断其是否为空,这么做就是有必要的
第二个问题,free释放内存是成功了,但指针的值还是指向原来分配的地址空间,但这个地址已经是无效的,如果使用会发生内存错误。必须你自己赋值才能把它设成NULL,即:
root = NULL;
你free(root)后判断其是否为空,这么做就是有必要的
追问
第一个问题的回答,我没太看懂,我没有说有两个程序呀,我是想问删除链表为什么要最后才删除head头指针。第二个问题,我并没有疑惑NULL是电脑自动生成的,我是不知道free删除指针后,原来的指针还能不能用,因为我看有些解释说的是内存被释放只是可以重新利用,里面的东西没有变。然后我发现free(a);a->next 不能用。所以我想问一下大佬们 free删除的机制是啥,删除后还剩下啥
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
你这个两问题要倒过来回答:
首先是第二个问题,你的想法是错误的,因为指针一旦释放了,就不可以继续访问,否则就会出现程序崩溃。至于为什么这样呢?你要先理解内存的分配机制。这个讲起来有点复杂,如果用一次化学实验来比喻的话大概就是这样的:
整个计算机系统就像是一个大的化学实验室,而内存就是一个个用于存放化学材料的烧杯,然后操作系统是这些烧杯的管理员。而我们去做实验的时候,要通过malloc向管理员申请烧杯来装东西,然后使用完了之后,要通过free把这些烧杯归还管理员,以便其他人使用。那么一旦归还了烧杯,虽然烧杯还在,但你已经无权使用,所以不能再访问了,再访问系统就会判断你违规使用了别人的烧杯,把你赶出实验室。
至于第二个问题,理解了第一个问题,第一个问题应该不是问题。只需要用一个循环逐个删除释放链表的元素就可以了。
首先是第二个问题,你的想法是错误的,因为指针一旦释放了,就不可以继续访问,否则就会出现程序崩溃。至于为什么这样呢?你要先理解内存的分配机制。这个讲起来有点复杂,如果用一次化学实验来比喻的话大概就是这样的:
整个计算机系统就像是一个大的化学实验室,而内存就是一个个用于存放化学材料的烧杯,然后操作系统是这些烧杯的管理员。而我们去做实验的时候,要通过malloc向管理员申请烧杯来装东西,然后使用完了之后,要通过free把这些烧杯归还管理员,以便其他人使用。那么一旦归还了烧杯,虽然烧杯还在,但你已经无权使用,所以不能再访问了,再访问系统就会判断你违规使用了别人的烧杯,把你赶出实验室。
至于第二个问题,理解了第一个问题,第一个问题应该不是问题。只需要用一个循环逐个删除释放链表的元素就可以了。
追问
很感谢你生动的例子,现在我明白第二个问题了。
但是第一个问题,其实我倒不是一点不懂,但是我查了一些答案,都是最后才释放head(头节点),这一点我有点没想通,我觉着head和其余的节点是相同的,可以在确定下一个指向的时候删除head,希望您能解释一下。
追答
第一个问题,你的理解是正确的。之所以很多人最后才删除头节点,只是出于方便,也可以从头节点开始删除啊。比如这样就可以从头节点开始删除了。
p=head;
for(;p!=NULL;)
{n=p->next;
free(p);
p=n;}
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
首先,可以free的内存区域都是你程序公用内存,因此你free后,有一定可能立刻被程序利用来做其他数据存储了,因此你不可以相信free后a->next还是有效的
下面是一个删除单向链表的算法:
a=head; //取得头节点
while ( a ) { b=a->next; free(a); a=b; } //如果当前节点有效,取得后续节点指针到b,然后删除a指向节点,并且让a重新复制成下一节点指针(准备下次循环删除)
head=NULL; //删除完毕,清除已经无效的head指针
下面是一个删除单向链表的算法:
a=head; //取得头节点
while ( a ) { b=a->next; free(a); a=b; } //如果当前节点有效,取得后续节点指针到b,然后删除a指向节点,并且让a重新复制成下一节点指针(准备下次循环删除)
head=NULL; //删除完毕,清除已经无效的head指针
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
回答仅供参考
1、以单向链表为例,一个头节点+N个数据节点,删除链表时,应先删除尾节点,从后往钱删除。如果直接把头节点删了,后续的数据节点就找不到了,造成内存泄漏。
2、释放指针a后,一定要将a置NULL。举例:假如a指向内存地址0x8000,如果仅仅free(a),a仍然指向内存0x8000,由于a已经释放了对内存0x8000的占用,该内存可能在后续被其他变量占用,如此时定义了一个指针b恰好也指向0x8000,此时b就占用了这块内存。由于a没有置NULL,仍然指向0x8000,若此时仍然操作a,将改变0x8000内存块中的数据,这样将导致不可预料的后果。相反,若之前将a置NULL后,下次使用时,必须给a分配一块内存,就不会有上述问题。
1、以单向链表为例,一个头节点+N个数据节点,删除链表时,应先删除尾节点,从后往钱删除。如果直接把头节点删了,后续的数据节点就找不到了,造成内存泄漏。
2、释放指针a后,一定要将a置NULL。举例:假如a指向内存地址0x8000,如果仅仅free(a),a仍然指向内存0x8000,由于a已经释放了对内存0x8000的占用,该内存可能在后续被其他变量占用,如此时定义了一个指针b恰好也指向0x8000,此时b就占用了这块内存。由于a没有置NULL,仍然指向0x8000,若此时仍然操作a,将改变0x8000内存块中的数据,这样将导致不可预料的后果。相反,若之前将a置NULL后,下次使用时,必须给a分配一块内存,就不会有上述问题。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询