赞
踩
在学习C++/数据结构的链表部分时,我留意到了一处有关于关键字delete的操作细节。new和delete是C++中经常成对使用的关键字,用于开辟/删除内存空间、并将地址赋值于等号左边指针变量;关于delete,边学习边刷链表题时留意到使用delete清除临时指针变量、释放内存的操作,结合要防止指针ptr成为野指针的目的,通常还需要加一条如
p
t
r
=
n
u
l
l
p
t
r
ptr=nullptr
ptr=nullptr来达成。
而在一开始学习接触时,混淆应该是先delete指针内存、还是先清空指针内容,即搞不清楚两条语句的顺序,因此写了小小的一个测试例子,Debug看一下对比效果。
初始化定义好指针指向链表头节点后,赋值临时指针ptr,然后将其赋值为指向空指针,再delete释放内存。
int arr1[3]={1,2,3};
Node *head=gen_listnode(arr1,3);
Node *ptr=head;
ptr=nullptr;
delete ptr;
设置断点启动Debug,可以看到再经历先赋值为空再delete掉指针的话,只是指针变量ptr自己被清空,自身占用内存被释放;而该指针ptr指向的节点变量head没有被清除(即ptr指向内存没被清空):
当然,肯定有小伙伴问,直接赋值为null不就完事了,为啥还要delete?这是因为如果不delete的话,cpu中该指针变量实际上仍然存在,只不过现在为空指针没指向任何变量而已——但本身仍然在占用该地址/消耗内存呢,因此还需要delete掉解除占用,这样原指针变量的那块“地盘”才能恢复给cpu动态赋予其他变量申请使用,总不能“占着茅坑不拉屎”对吧!
如果对该指针变量ptr先使用delete、再赋值为空的话,即有:
/* 指针变量中,存储的是指向的变量的地址符; */
int c1=&a;
int c2=p;
printf("%d\n",c1);
printf("%d\n",c2);
//可以看到c1和c2输出结果一样,说明指针里面存的就是指向的变量的地址~
在delete之前:
指针ptr在指向链表节点head;
在delete执行后:
由于ptr指向了head所在地址,delete了指针ptr实际上即把head占用的内存也给释放掉了,这时,原地址上的变量(链表节点)随同ptr指针,经内存被释放、指针成为了指向“未知”的野指针:
为避免这样的野指针指向“未知”的空间,防止在之后重定义使用该变量名时可能产生难以想象的错误,必须禁止野指针的出现!必须禁止野指针的出现!(这或许算是C/C++编程中需要牢记的一项法则了吧。。),因此,还需要对该指针变量赋为空指针——即不指向任何内存空间,这样后再来看,节点变量head和指向他的指针ptr此时都为空指针/(NULL)了:
因为head并不是节点变量的真实名,而是一个new出来的指向真实变量地址的指针(在前文描述中把他称为节点变量只是方便区分和ptr指针的描述,实际就是俩指向同一块地址的俩指针。。),所以在操作
p
t
r
=
n
u
l
l
p
t
r
ptr=nullptr
ptr=nullptr后head并没有随同ptr指针被清空,如果你看着这个head也挺碍眼的话,可以一起
h
e
a
d
=
p
t
r
=
n
u
l
l
p
t
r
head=ptr=nullptr
head=ptr=nullptr的啦哈哈哈。
当然,就我这里链表部分的学习内容来说,delete+清空为NULL这套操作一般是用于删除链表节点的,而链表节点没有单独说存在一个所谓“真实变量名”(或者说,毕竟你的链表节点是“new”出来的,有new才有的delete,new生成的一定是指针变量),节点的链接指向是通过上一链表节点存放其所在地址来供用户“索引"的,如果你加了个临时指针变量ptr指向它,并采用上文对指针ptr先delete再清空为NULL的话,这块地址上的东西确实被解除内存占用且清空了,就不用担心存在上图这样“别扭”的状况啦。~~
#include <iostream> using namespace std; typedef struct ListNode{ int val; ListNode* next; ListNode():val(0),next(nullptr) {} ListNode(int x):val(x),next(nullptr) {} ListNode(int x,ListNode *p):val(x),next(p) {} }Node; Node* gen_listnode(int *arr,int _size) { int k=_size; Node *ptr=new Node(arr[0]); Node *_head=ptr; for(k=1;k<_size;k++) { ptr->next=new Node(arr[k]); ptr=ptr->next; } return _head; } int main(void) { int arr1[3]={1,2,3}; Node *head=gen_listnode(arr1,3); Node *ptr=head; //这里放个断点,往下执行,感受下~ //先清空指针,再释放指针内存 ptr=nullptr; delete ptr; Node *head=gen_listnode(arr1,3); Node *ptr=head; //换断点到这,往下执行,感受下~ //先释放指针及指向内存,再清空指针 delete ptr; head=ptr=nullptr; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。