指针是一种特殊的变量,只能用来存储内存的地址,使用 * 号表示其是一个指针。指针是 C++ 中非常重要的概念,它让我们能够直接操作内存,实现更灵活的数据处理。
下面通过一个例子来理解指针的核心原理:
int a = 42;
int *p = &a;1变量名 内存地址 存储的值
2------ -------- --------
3a 0x1000 42
4p 0x2000 0x1000 ──────┐
5 │
6 ┌──────────────────────────┘
7 │ p 存储了 a 的地址
8 ▼
9 0x1000 → 42 (*p 可以访问 a 的值)指针p本身也是一个变量,有自己的地址(0x2000),但它存储的内容不是普通数据,而是另一个变量a的地址(0x1000)。通过*p(解引用)就能顺着这个地址找到a的值 42。
定义指针时需要指明指针指向内存所存储的数据类型及指针名称。
常见的指针定义方式如下:
int *ptr_i; // 指针指向地址只能存储int类型数据
double *ptr_d; // 指针指向地址只能存储double类型数据
char *ptr_c; // 指针指向地址只能存储char类型数据
bool *ptr_b; // 指针指向地址只能存储bool类型数据指针有三种常见的赋值方式:
赋值为空指针,表示指针不指向任何有效地址:
int *ptr = nullptr;赋值为一个已存在变量的内存地址,使用取地址运算符 &:
int number = 5;
int *ptr = &number;赋值为动态开辟的内存地址,使用 new 关键字:
int *ptr = new int;使用指针中存储的地址,直接输出指针即可。
int number = 5;
int *ptr = &number;
cout << ptr << endl; // 输出number变量的地址使用指针中存储的地址中保存的数据,需要使用指针解引用的方式,即在指针名字之前加一个 * 号。
int number = 5;
int *ptr = &number;
cout << *ptr << endl; // 输出number变量内存储的数据,即5使用指针变量自己的地址时,需要使用取地址运算符,即在指针的名字前面加上一个 & 符号。
int number = 5;
int *ptr = &number;
cout << &ptr << endl; // 输出ptr变量的地址按指针传递是指将实际参数的地址传递给函数参数,通过指针操作可以修改实际参数的值。
优点:
缺点:
1void foo(int *x) {
2 *x = 20;
3}
4
5int main() {
6 int a = 10;
7 foo(&a);
8 // a的值被修改为20
9 return 0;
10}动态内存是指在程序运行时动态分配的内存,使用 new 的方式开辟,使用 delete 的方式释放。
int *ptr = new int(3);
*ptr = 5;
delete ptr;
ptr = nullptr;动态内存使用注意事项:
delete 进行释放nullptr,否则指针就会变成野指针/悬挂指针使用动态内存的优点:
下面通过具体的内存示意图,展示指针的工作过程。
例1:指针指向已有变量
int number = 42;
int *ptr = &number;变量名 内存地址(示意) 存储的值
------ ------------ --------
number 0x1000 42
ptr 0x2000 0x1000 (存储的是number的地址)1操作:
2cout << number; → 输出 42 (直接访问变量的值)
3cout << &number; → 输出 0x1000 (获取变量的地址)
4cout << ptr; → 输出 0x1000 (指针存储的地址)
5cout << *ptr; → 输出 42 (解引用:访问指针指向地址上的值)
6cout << &ptr; → 输出 0x2000 (指针变量自身的地址)例2:通过指针修改变量的值
int a = 10;
int *p = &a;
*p = 20; // 通过指针修改a的值
cout << a; // 输出20,a的值被修改了执行前: 执行 *p = 20 后:
a [0x1000]: 10 a [0x1000]: 20
p [0x2000]: 0x1000 p [0x2000]: 0x1000(不变)*p = 20的含义是:找到p指向的地址(0x1000),将该地址上的值修改为 20。因为a就在这个地址上,所以a的值也变了。
例3:按指针传参的执行过程
1void swap(int *x, int *y) {
2 int temp = *x;
3 *x = *y;
4 *y = temp;
5}
6
7int main() {
8 int a = 3, b = 7;
9 swap(&a, &b);
10 // 现在 a=7, b=3
11}1调用前:a=3(地址0x1000), b=7(地址0x1004)
2调用 swap(&a, &b):x=0x1000, y=0x1004
3
4执行 temp = *x; → temp = 3
5执行 *x = *y; → 地址0x1000的值改为7,即a=7
6执行 *y = temp; → 地址0x1004的值改为3,即b=3
7
8返回后:a=7, b=3 → 交换成功!例4:动态内存的生命周期
int *ptr = new int(100); // 在堆上分配内存,存储值100
cout << *ptr; // 输出 100
*ptr = 200; // 修改为 200
delete ptr; // 释放内存
ptr = nullptr; // 避免野指针new int(100)后: ptr → [堆内存: 100]
*ptr = 200后: ptr → [堆内存: 200]
delete ptr后: ptr → [已释放内存] ← 危险!此时ptr是野指针
ptr = nullptr后: ptr → [空] ← 安全使用指针解决问题的一般思路:
nullptr* 解引用访问或修改数据,通过指针名直接获取地址new,用完后一定要 delete,并将指针设为 nullptrint p; p = 5;),指针指向的是随机地址,会导致程序崩溃 的两种含义*:在定义时 int p 中的 表示"这是一个指针";在使用时 p 表示"解引用,访问指针指向的值"。两者含义不同&:将变量赋给指针时忘记加 &,如 int p = number; 应该写成 int p = &number;nullptr,之后再次使用该指针会导致未定义行为(野指针/悬挂指针)new 分配的单个变量用 delete 释放,new[] 分配的数组用 delete[] 释放,两者不能混用