CPP学习笔记—指针
一、指针到底是什么?—— 内存地址的“房卡”
想象一下计算机的内存是一家长长的酒店,里面有无数的房间,每个房间都有一个独一无二的门牌号(内存地址)。
普通变量:就像一个房间,里面存放着具体的东西(值)。
1
int age = 25; // 在一个叫 `age` 的房间里,放了数字 25。
指针:它本身也是一个变量,但它里面存放的不是普通的东西,而是一张房卡。这张房卡上写着另一个房间的门牌号。
所以,指针是一个存储了另一个变量内存地址的变量。通过这张“房卡”,我们就能找到并操作那个特定的“房间”。
二、两大核心操作符:&
(取地址) 和 *
(解引用)
要玩转指针,必须掌握这两个“魔法”操作符。
1. &
(取地址符) —— “制作房卡”
&
符号的作用是获取一个变量的内存地址。可以把它读作“…的地址”。
1 | int age = 25; // 一个存放 25 的房间 `age` |
2. *
(解引用/间接访问符) —— “刷卡进门”
*
符号的作用是访问指针所指向的地址中存储的值。可以把它读作“访问…所指向地址里的值”。
1 | std::cout << *p_age; // 输出 25 |
小结: &
是从值到地址,*
是从地址到值。它们是一对互逆的操作。
三、为什么我们需要指针?—— C++的“超能力”
直接用 age
不就行了,为什么要多此一举用指针?问得好!指针之所以重要,主要体现在以下几个方面:
1. 高效的函数传参
想象一个函数需要处理一个非常大的数据结构(比如一个包含一百万个元素的数组)。
- 不使用指针(传值):函数会把整个百万元素的数组完整地复制一份。这既浪费时间又浪费内存。
- 使用指针(传址):只需要把数组的“房卡”(一个仅占 8 字节的地址)复制给函数。函数通过这张小小的房卡,就能直接访问和修改原始的、巨大的数组。效率天差地别!
1 | // 假设 BigData 是一个很大的结构体 |
2. 动态内存管理
有时候,我们在写代码时并不知道程序运行时需要多少内存。比如,用户可能要处理 10 个文件,也可能要处理 1000 个。指针允许我们在程序运行时,按需向操作系统申请内存(在“堆”上)。
new
:向系统申请一块新内存(建一个新房间),并返回一个指向它的指针(一张新房卡)。delete
:告诉系统这块内存我用完了,你可以回收了(退房)。
1 | int* dynamic_array; |
3. 实现多态
在面向对象编程中,我们可以用基类的指针指向派生类的对象,从而实现多态,让代码更加灵活和可扩展。这是 C++ 高级特性之一,其基础就是指针。
四、指针的“危险地带”:必须知道的注意事项
指针的灵活性也带来了风险:
1. 野指针 (Wild Pointer)
一个未经初始化的指针,它的指向是完全随机的,就像一张印着未知门牌号的房卡。使用它就像在酒店里乱刷卡,可能会闯入不该进的房间,导致程序崩溃。
1 | int* p; // 野指针!它指向哪里完全未知。 |
防御方法:在定义指针时,立即初始化!
2. 空指针 (Null Pointer)
为了安全,当我们暂时没有明确的目标让指针指向时,应该给它一个特殊的值 nullptr
(C++11 推荐)。这就像一张被明确标记为“无效”的房卡。
1 | int* p = nullptr; // 好习惯!明确表示p不指向任何东西。 |
3. 悬挂指针 (Dangling Pointer)
当指针指向的内存已经被释放(delete
),但指针本身没有被置为 nullptr
时,它就成了悬挂指针。这就像退了房,但房卡还留在手里,而那个房间可能已经分给了下一位客人。此时再用这张房卡,后果不堪设想。
1 | int* p = new int(5); |
防御方法:释放内存后,立即将指针置为 nullptr
。
1 | delete p; |
4. 内存泄漏 (Memory Leak)
如果用 new
申请了内存,但在程序结束前忘记用 delete
释放它,这块内存就“丢失”了。它既不能被程序使用,也无法被系统回收。这就像不断开新房间但从不退房,最终会导致酒店(系统)没有可用房间(内存耗尽)。
防御方法:确保每一个 new
都有一个对应的 delete
(或 delete[]
)。
五、现代C++的救赎:智能指针
手动管理内存(new
/delete
)既繁琐又容易出错。为了解决这个问题,现代 C++(C++11及以后)引入了智能指针,这才是我们现在应该优先使用的工具!
智能指针本质上是一个类,它包装了原始指针,并利用类的构造函数和析构函数来自动管理内存的生命周期。
std::unique_ptr
:独占所有权的智能指针。当它被销毁时,它所管理的内存会自动释放。保证了任何时候只有一个指针指向资源。std::shared_ptr
:共享所有权的智能指针。它使用引用计数,只有当最后一个指向资源的shared_ptr
被销毁时,内存才会被释放。
1 |
|
黄金法则: 在现代 C++ 编程中,优先使用智能指针来管理动态分配的内存,只有在与旧的 C API 交互或特定性能优化场景下,才考虑使用原始指针。
总结
指针是 C++ 的核心,也是它的魅力所在。它赋予了我们直接与内存对话的能力。
- 核心是地址:指针存储的是地址。
&
和*
是钥匙:&
用来获取地址,*
用来通过地址访问内容。- 能力伴随风险:务必警惕野指针、悬挂指针和内存泄漏。
- 拥抱现代 C++:尽可能使用智能指针,让编译器处理繁琐的内存管理。