C++ 指针运算符(& 和 *)(超详细)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言:为什么需要学习指针运算符?
在 C++ 编程中,指针运算符 &
(取地址符)和 *
(解引用符)是理解内存管理与低级操作的关键工具。它们不仅是语言特性的一部分,更是实现复杂数据结构(如动态内存分配、链表、树等)的基石。对于初学者而言,这两个符号容易混淆,甚至可能引发内存错误;而中级开发者则需要通过深入理解其行为来优化代码性能。本文将从基础概念逐步展开,结合实际案例解析 &
和 *
的作用机制,并提供常见问题的解决方案。
一、指针基础:内存地址与变量的映射关系
1.1 变量的内存地址
在计算机内存中,每个变量都占据一块连续的空间,这块空间拥有唯一的地址(即内存位置)。例如:
int number = 10;
当声明 number
时,系统为其分配内存空间,并将数值 10
存储在该地址中。此时,&
运算符的作用是获取变量的地址。
1.2 指针:存储地址的变量
指针是一种特殊类型的变量,其值为另一个变量的内存地址。例如:
int* pointer = &number; // pointer 存储了 number 的地址
这里,int*
表示 pointer
是一个指向 int
类型的指针,而 &number
则通过 &
运算符获取 number
的地址。
二、& 运算符:取地址符的深层解析
2.1 基本语法与功能
&
运算符用于获取变量的内存地址。语法形式为:
地址值 = &变量名;
例如:
int x = 5;
int* px = &x; // px 现在存储 x 的地址
2.2 比喻理解:房子与门牌号
想象变量 x
是一栋房子,x
的地址就像它的门牌号。&
运算符的作用是“写下这个门牌号”,而指针变量(如 px
)则像一个信封,专门用来存放这个门牌号。
2.3 常见应用场景
- 动态内存分配:通过
new
分配内存时,&
可以帮助获取分配空间的地址。 - 函数参数传递:当需要修改函数外部的变量时,必须通过指针(即地址)传递。
三、* 运算符:解引用符与内存值的访问
3.1 基本语法与功能
*
运算符用于访问指针所指向的内存地址中的值。语法形式为:
值 = *指针;
例如:
int y = *px; // y 的值为 5,等价于访问 x 的内存空间
3.2 比喻理解:通过门牌号进入房间
假设 px
存储了 x
的门牌号(地址),*px
就像“拿着门牌号找到对应的房间,并取出里面的物品(值)”。
3.3 注意事项
- 空指针访问:若指针未初始化或指向无效地址,解引用会导致未定义行为(如程序崩溃)。
- 类型匹配:指针类型必须与解引用后的变量类型一致,否则可能引发数据损坏。
四、综合案例:通过指针操作变量
4.1 基础示例:变量与指针的交互
#include <iostream>
int main() {
int num = 20;
int* pNum = # // 获取 num 的地址
std::cout << "Address of num: " << &num << std::endl;
std::cout << "Value via pointer: " << *pNum << std::endl; // 输出 20
*pNum = 30; // 通过指针修改 num 的值
std::cout << "Modified num: " << num << std::endl; // 输出 30
return 0;
}
4.2 进阶案例:数组与指针的结合
C++ 中数组名本质上是地址的常量指针。例如:
int arr[3] = {1, 2, 3};
int* ptr = arr; // ptr 指向数组第一个元素的地址
std::cout << "Value at first element: " << *ptr << std::endl; // 输出 1
std::cout << "Address of second element: " << &arr[1] << std::endl;
此时,ptr + 1
表示指向第二个元素的地址,而 *(ptr + 1)
即访问其值。
五、常见误区与解决方案
5.1 误区一:混淆指针与指针指向的值
int a = 10;
int* p = &a;
int* q = p; // q 和 p 指向同一地址
*q = 20; // 此时 a 的值变为 20
关键点:指针变量存储地址,通过 *
可以修改目标变量的值。
5.2 误区二:未初始化指针
int* invalid_ptr; // 未初始化,指向随机地址
std::cout << *invalid_ptr; // 程序可能崩溃
解决方案:始终在声明指针时初始化,或立即赋值有效地址。
5.3 误区三:误解 &
在函数参数中的作用
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 1, y = 2;
swap(&x, &y); // 通过地址传递实现值交换
return 0;
}
此处 &x
将变量地址传递给函数,使得 swap
能修改原始变量的值。
六、进阶应用:指针运算符在复杂场景中的实践
6.1 动态内存分配与释放
int* dynamicArray = new int[5]; // 分配 5 个 int 的内存空间
dynamicArray[0] = 10; // 等价于 *(dynamicArray + 0) = 10
delete[] dynamicArray; // 释放内存
通过 new
和 delete
,程序员可直接管理内存,但需谨慎避免内存泄漏。
6.2 结构体与指针
struct Person {
char name[50];
int age;
};
Person person;
Person* pPerson = &person;
pPerson->age = 30; // 等价于 (*pPerson).age = 30
这里 ->
运算符简化了对结构体内成员的访问,本质是 *
和 .
的组合。
七、总结与学习建议
7.1 核心要点回顾
&
运算符:获取变量的内存地址,用于初始化指针。*
运算符:访问指针指向的内存值,可修改目标变量的值。- 安全实践:始终确保指针指向有效地址,避免解引用空指针。
7.2 进一步学习路径
- 研究指针与数组、函数指针、C++ 智能指针(如
std::unique_ptr
)的结合使用。 - 通过调试工具(如 GDB)观察变量地址与指针的内存交互。
- 阅读《C++ Primer》或《Effective C++》中关于指针的章节。
结论:掌握指针运算符是通往高效编程的必经之路
C++ 指针运算符(&
和 *
)不仅是语言的核心特性,更是理解计算机底层原理的窗口。通过本文的案例与解析,读者应能逐步建立清晰的指针操作逻辑,并在实际项目中避免常见错误。记住:指针如同双刃剑,合理使用可提升性能,但误操作也可能导致程序崩溃。建议通过编写简单程序逐步实践,最终实现从“理解概念”到“熟练应用”的跨越。