尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

小学生学C++编程语法知识(C++野指针与悬空指针)

小学生学C++编程语法知识(C++野指针与悬空指针) 一、先回忆一下指针到底是什么假设我们有一个小盒子int x 10;内存中可以想象成变量 x ┌─────────┐ │ 10 │ └─────────┘ ↑ │ 地址如果int *p x;那么p ┌─────────┐ │ x │ ───────→ x └─────────┘ ┌─────┐ │ 10 │ └─────┘所以p 是一个指针它里面存放的是 x 的地址。我们可以通过cout *p;找到 x得到10二、什么是“野指针”先看一个非常危险的例子int *p; cout *p;这里的p是什么我们只声明了int *p;但是没有让 p 指向任何合法的地方。就像你手里拿着一把钥匙但是你根本不知道这把钥匙是哪扇门的。甚至这把“钥匙”里面可能装着一个完全乱七八糟的地址。于是*p就相当于“我偏要去打开这个不知道是什么地方的门”这就是非常危险的。这种没有经过正确初始化、指向未知内存位置的指针我们通常称为野指针Wild Pointer例如int *p; // 野指针 *p 10; // 危险三、为什么int *p;很危险初学者特别容易认为int *p;是不是相当于int *p nullptr;不是这是两个完全不同的东西。情况1没有初始化int *p;p中的地址是不确定的。可以理解成p ┌──────────────┐ │ ???????? │ └──────────────┘不知道它指向哪里。情况2初始化为 nullptrint *p nullptr;这时候我们明确告诉计算机“这个指针现在谁也不指。”可以理解成p ┌──────────────┐ │ 不指向任何地方 │ └──────────────┘所以int *p nullptr;比int *p;安全得多。四、还有一种常见的野指针比如int *p (int*)100;这里我们让p指向地址100。但是地址 100 是不是一个合法的int对象我们根本不知道。于是*p 20;就可能出问题。所以随便给指针一个地址让它指向一个自己并不知道是否有效的地方也可能形成野指针。五、那么什么是“悬空指针”这个更有意思。悬空指针一开始可能是一个完全正常的指针。例如int *p new int(10); cout *p;此时p │ ↓ ┌─────┐ │ 10 │ └─────┘一切正常。但是我们执行delete p;发生了什么原来的那块动态内存已经被释放了。可以想象成p │ ↓ ┌─────┐ │ 10 │ └─────┘ ↑ 已经被释放但是注意p 这个指针变量本身还在那里它里面仍然保存着原来的地址。于是cout *p;就危险了。因为p 还拿着“旧房子的地址”但是这个房子已经不存在了。这种指针就叫悬空指针Dangling Pointer六、野指针和悬空指针有什么区别这是今天最重要的知识。我们可以用两个故事来理解。① 野指针一出生就不知道去哪int *p;它一开始就没有被正确初始化。就像小朋友拿着一张没有写地址的纸条说“我要去找一个房子”但是根本不知道房子在哪里。这就是野指针。② 悬空指针原来有家后来家没了例如int *p new int(10); delete p;刚开始p ─────→ 房子后来delete p;房子被拆掉了p ─────→ ❌ 原来的房子已经不存在但是p还保存着那个旧地址。这就是悬空指针。七、用一张表彻底分清对比野指针悬空指针英文Wild PointerDangling Pointer一开始是否有效通常没有通常曾经有效原因没初始化、指向未知地址等指向的对象已经被释放/销毁比喻一开始就不知道去哪原来的房子已经拆了常见例子int *p;delete p;后仍使用p核心问题不知道指向哪里指向的东西已经不存在一句话野指针不知道指向谁。悬空指针曾经知道指向谁但那个人已经不在了。八、最危险的地方它们都可能导致程序出问题例如int *p; *p 10;这里可能出现程序异常 程序崩溃 访问非法内存而int *p new int(10); delete p; *p 20;同样非常危险。这就是所谓的非法内存访问。不过要特别告诉小朋友不要认为“运行没有报错”就代表代码正确。比如int *p new int(10); delete p; cout *p;有时候可能打印出10有时候可能打印其他数字。有时候程序直接出问题。为什么因为delete以后这块内存已经不再属于我们了。九、一个特别容易犯的错误看这个程序int *p new int(10); delete p; cout *p;问题在哪里很多小朋友会说“p 里面有地址呀”没错。但是有地址 ≠ 这个地址对应的对象还存在。这是理解悬空指针最关键的一句话。十、解决悬空指针的方法delete 后置空我们可以这样写int *p new int(10); delete p; p nullptr;现在delete p ↓ 原来的对象消失 ↓ p nullptr ↓ p明确表示我现在不指向任何对象因此推荐形成一个好习惯delete p; p nullptr;十一、但是这里还有一个小陷阱有的小朋友可能认为int *p new int(10); delete p; p nullptr; cout *p;是不是就安全了还是不安全因为*p相当于“访问 p 指向的对象。”可是p nullptr它根本没有指向任何对象。所以正确做法是if (p ! nullptr) { cout *p; }十二、为什么现代 C越来越少直接使用new和delete这是一个很重要的进阶知识。以前我们经常看到int *p new int(10); delete p;但是现代 C 更推荐使用vector string unique_ptr shared_ptr等工具来帮助管理资源。例如vectorint a;通常不需要我们自己new delete这样就能大大降低忘记释放内存、悬空指针、内存泄漏等问题。所以学习指针并不是为了让我们以后疯狂写new delete而是为了让我们真正理解C是如何管理内存的。十三、记忆口诀最后送大家一个非常容易记的口诀野指针出生就迷路悬空指针原来有家后来家没了nullptr我现在谁也不指delete把动态对象释放掉delete 后置 nullptr防止继续拿旧地址乱跑可以画成野指针 p ─────→ ?????? 不知道是谁正常指针 p ─────→ [ 10 ]悬空指针 p ─────→ [ 已经被释放 ] ❌安全一些的状态 p ─────→ nullptr ↓ 谁也不指十四、给同学们留一个思考题下面四个p哪些存在问题①int *p;②int *p nullptr;③int x 10; int *p x;④int *p new int(10); delete p;答案①野指针②空指针但不是野指针③正常指针④此时p已经成为悬空指针尤其要记住空指针 ≠ 野指针 ≠ 悬空指针。这三个概念放在一起理解才算真正把 C 指针的“危险三兄弟”分清楚了。
返回列表