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; // 获取 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;         // 释放内存  

通过 newdelete,程序员可直接管理内存,但需谨慎避免内存泄漏。

6.2 结构体与指针

struct Person {  
    char name[50];  
    int age;  
};  

Person person;  
Person* pPerson = &person;  
pPerson->age = 30; // 等价于 (*pPerson).age = 30  

这里 -> 运算符简化了对结构体内成员的访问,本质是 *. 的组合。


七、总结与学习建议

7.1 核心要点回顾

  • & 运算符:获取变量的内存地址,用于初始化指针。
  • * 运算符:访问指针指向的内存值,可修改目标变量的值。
  • 安全实践:始终确保指针指向有效地址,避免解引用空指针。

7.2 进一步学习路径

  1. 研究指针与数组、函数指针、C++ 智能指针(如 std::unique_ptr)的结合使用。
  2. 通过调试工具(如 GDB)观察变量地址与指针的内存交互。
  3. 阅读《C++ Primer》或《Effective C++》中关于指针的章节。

结论:掌握指针运算符是通往高效编程的必经之路

C++ 指针运算符(&*)不仅是语言的核心特性,更是理解计算机底层原理的窗口。通过本文的案例与解析,读者应能逐步建立清晰的指针操作逻辑,并在实际项目中避免常见错误。记住:指针如同双刃剑,合理使用可提升性能,但误操作也可能导致程序崩溃。建议通过编写简单程序逐步实践,最终实现从“理解概念”到“熟练应用”的跨越。

最新发布