Cpp指针的delete操作 - 小记

Cpp指针的delete操作 - 小记

  在学习C++/数据结构的链表部分时,我留意到了一处有关于关键字delete的操作细节。new和delete是C++中经常成对使用的关键字,用于开辟/删除内存空间、并将地址赋值于等号左边指针变量;关于delete,边学习边刷链表题时留意到使用delete清除临时指针变量、释放内存的操作,结合要防止指针ptr成为野指针的目的,通常还需要加一条如 p t r = n u l l p t r ptr=nullptr ptr=nullptr来达成。
而在一开始学习接触时,混淆应该是先delete指针内存、还是先清空指针内容,即搞不清楚两条语句的顺序,因此写了小小的一个测试例子,Debug看一下对比效果。

1.先赋值为空,再delete

初始化定义好指针指向链表头节点后,赋值临时指针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指向内存没被清空):对指针先赋值为空->再delete清除
当然,肯定有小伙伴问,直接赋值为null不就完事了,为啥还要delete?这是因为如果不delete的话,cpu中该指针变量实际上仍然存在,只不过现在为空指针没指向任何变量而已——但本身仍然在占用该地址/消耗内存呢,因此还需要delete掉解除占用,这样原指针变量的那块“地盘”才能恢复给cpu动态赋予其他变量申请使用,总不能“占着茅坑不拉屎”对吧!

2.先delete,再赋值为空指针

  如果对该指针变量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;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值