一张图区分常量指针和指针常量

本文通过直观的图表对比,帮助C++初学者区分常量指针与指针常量的概念,深入解析两者间的不同及其应用场景。

常量指针(const pointer)和指针常量(pointer to const)是 C++ 初学者容易搞混的部分,我发现如何完善文字表述都不如上图痛快。

每一列的左边方框代表存放指针的内存,右边代表一段存放变量的内存,笑脸代表变量。

当然可以!我们来**系统、清晰、深入浅出地介绍“指针”**,这是 C/C++ 编程中最强大也最容易让人困惑的概念之一。 --- ## 🌟 什么是指针? > **指针是一个变量,它存储的是另一个变量的内存地址。** 你可以把它想象成一个“门牌号”——不是房子本身,而是告诉你房子在哪里。 ### ✅ 类比理解: | 生活比喻 | 计算机对应 | |--------|-----------| | 门牌号(如:北京市朝阳区XX路10号) | 内存地址(如:`0x7fff5fbff6c4`) | | 房子本身住着人 | 变量中存着数据(比如 `int x = 10;`) | | 指着门牌号的纸条 | 指针变量(比如 `int *p;`) | 👉 所以: ```cpp int x = 10; int *p = &x; // p 是指针,保存了 x 的地址 ``` → 就像你写了一张纸条:“x 的值在地址 0x... 处”。 --- ## 🔧 指针的基本语法 ### 1. 定义指针 ```cpp int *p; // p 是一个指向 int 类型变量的指针 float *fp; // fp 指向 float char *cp; // cp 指向 char ``` ### 2. 取地址符:`&` 获取某个变量的内存地址。 ```cpp int x = 5; cout << &x; // 输出类似 0x7fff5fbff6c4 ``` ### 3. 解引用:`*` 通过指针访问它所指向的值。 ```cpp int x = 10; int *p = &x; cout << *p; // 输出 10 → *p 就是“p 指向的那个数” *p = 20; // 修改 p 指向的内容 → 相当于 x = 20 ``` --- ## ✅ 示例代码:完整演示 ```cpp #include <iostream> using namespace std; int main() { int x = 10; int *p = &x; // p 指向 x cout << "x 的值: " << x << endl; // 10 cout << "x 的地址: " << &x << endl; // 如 0x7fff... cout << "p 中存的值: " << p << endl; // &x 一样 cout << "p 指向的值: " << *p << endl; // 10 *p = 99; // 改变 p 指向的值 → 改变了 x cout << "现在 x = " << x << endl; // 99! return 0; } ``` 输出: ``` x 的值: 10 x 的地址: 0x7fff5fbff6c4 p 中存的值: 0x7fff5fbff6c4 p 指向的值: 99 现在 x = 99 ``` --- ## 🎯 指针的核心作用(为什么需要它?) | 用途 | 说明 | |------|------| | ✅ **函数间传引用** | 实现“传址调用”,让函数能修改外部变量 | | ✅ **动态内存分配** | 使用 `new` / `malloc` 创建运行时才确定大小的空间 | | ✅ **数组字符串操作** | 数组名本质是指针,高效遍历 | | ✅ **构建复杂数据结构** | 链表、树、等都靠指针连接节点 | | ✅ **提高性能** | 避免复制大对象,直接传递地址 | --- ## 💡 常见用法详解 ### 1. 函数参数传指针(实现“双向通信”) ```cpp void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int main() { int x = 3, y = 5; swap(&x, &y); cout << x << " " << y << endl; // 输出 5 3 return 0; } ``` 👉 没有指针的话,函数只能拿到副本,改不了原值。 --- ### 2. 指针与数组 数组名本质上是一个常量指针。 ```cpp int arr[5] = {10, 20, 30, 40, 50}; int *p = arr; // p 指向 arr[0] for (int i = 0; i < 5; ++i) { cout << *(p + i) << " "; // 等价于 arr[i] } // 输出:10 20 30 40 50 ``` ✅ 其实 `arr[i] == *(arr + i)`,甚至 `*(arr + i) == *(i + arr)` → 所以 `i[arr]` 合法但不推荐 😂 --- ### 3. 动态内存分配 ```cpp int *p = new int(42); // 分配一个 int,初始化为 42 cout << *p << endl; // 输出 42 delete p; // 释放内存 int n = 10; int *arr = new int[n]; // 动态数组 for (int i = 0; i < n; ++i) { arr[i] = i * i; } delete[] arr; // 注意用 delete[] ``` ⚠️ 忘记 `delete` 会导致**内存泄漏** --- ### 4. 指针指针(二级指针) ```cpp int x = 100; int *p = &x; // p 是一级指针 int **pp = &p; // pp 是二级指针,指向 p cout << **pp; // 输出 100 ``` 📌 常用于: - 修改指针本身的值(如在函数中改变谁被指向) - 二维数组或动态二维数组 --- ## ⚠️ 指针常见错误 | 错误 | 后果 | 如何避免 | |------|------|---------| | 未初始化指针 | 指向随机地址 → 崩溃 | 初始化为 `nullptr` | | 访问空指针 | 程序崩溃 | 使用前检查 `if (p != nullptr)` | | 重复释放内存 | undefined behavior | `delete` 后设为 `nullptr` | | 野指针 | 指向已释放的内存 | 释放后置空 | | 越界访问 | 数据损坏 | 控制索引范围 | ```cpp int *p = nullptr; if (p) { cout << *p; // 不会执行,安全 } ``` --- ## 📚 总结:指针三要素 | 操作 | 符号 | 含义 | |------|------|------| | 取地址 | `&` | 获取变量地址 | | 解引用 | `*` | 访问指针指向的值 | | 指针变量声明 | `int *p` | p 是一个指向 int 的指针 | 🧠 **口诀记忆:** > - `&` 是“拿地址” > - `*` 是“看内容” --- ## ✅ 进阶概念预览(后续可深入学习) | 概念 | 说明 | |------|------| | 函数指针 | 指向函数的指针,用于回调、事件处理 | | 智能指针(C++11) | `unique_ptr`, `shared_ptr` 自动管理内存 | | `const` 指针 | 控制指针能否修改指向或内容 | | 悬空指针 vs 空指针 | 区分危险与安全状态 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值