C++指针使用
C++指针使用
- 指针定义
- 指针操作符
- const指针
- 数据不可变
- 地址不可变
- 地址、数据都不可变
- 指针与数组
- 指针与函数
- 指针与内存管理
- 分配内存
- 释放内存
- 引用
- 引用作为函数入参
- 引用作为函数出参
- 常量引用
- 使用引用场景
- 使用指针场景
- 智能指针
- std::unique_ptr
- std::shared_ptr
- std::weak_ptr
指针定义
数据类型 *指针名;
定义的时候赋初始值,避免野指针
int* p = nullptr;
//int* p = NULL;
//int* p = 0;
cout << "所占存储:" << sizeof(p) << endl;
cout << "地址:" << p << endl;
指针操作符
操作符 | 名称 | 作用 |
---|---|---|
& | 取地址符 | 获取变量 的内存地址 |
* | 解引用符 | 访问指针 所指向的内存中的值 |
int* p = nullptr;
int a = 10;
cout << "step1, a=" << a << " ; &a=" << &a << " ; p=" << p << endl;// p存放变量a的地址
p = &a;
cout << "step2, a=" << a << " ; &a=" << &a << " ; p=" << p << " ; *p=" << *p << endl;
const指针
数据不可变
const int* p
,指向常量数据的指针(数据不可改)
int a = 10, b = 10, c = 20;const int* p = &a;
cout << "p=" << p << ", *p=" << *p << endl;p = &b;
cout << "p=" << p << ", *p=" << *p << endl;p = &c;
cout << "p=" << p << ", *p=" << *p << endl;// 修改报错
// *p = 100;
cout << c << endl;
cout << "p=" << p << ", *p=" << *p << endl;c = 100;
cout << c << endl;
cout << "p=" << p << ", *p=" << *p << endl;
地址不可变
int* const p
,常量指针(地址不可改)
int a = 10, b = 10, c = 20;int* const p = &a;
cout << "p=" << p << ", *p=" << *p << endl;// 报错,地址不能变
// p = &b;
cout << "p=" << p << ", *p=" << *p << endl;// 修改报错
*p = 100;
cout << c << endl;
cout << "p=" << p << ", *p=" << *p << endl;c = 100;
cout << c << endl;
cout << "p=" << p << ", *p=" << *p << endl;
地址、数据都不可变
const int* const p
,两者皆不可改
int a = 10, b = 10, c = 20;const int* const p = &a;
cout << "p=" << p << ", *p=" << *p << endl;// 修改报错
//p = &b;
cout << "p=" << p << ", *p=" << *p << endl;// 修改报错
//*p = 100;
指针与数组
1、
int *p = a;
与int *p = &a[0];
int a[] = { 1, 2, 3, 4, 5 };
int* p = a;
//int* p = &a[0];cout << "*p= " << *p << endl;
cout << "*(p+1)= " << *(p + 1) << endl;
cout << "p[2]= " << p[2] << endl;
指针与函数
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}int main()
{int a = 10, b = 20;cout << "交换前:a=" << a << " , &a=" << &a << endl;cout << "交换前:b=" << b << " , &b=" << &b << endl;swap(&a, &b);cout << "交换后:a=" << a << " , &a=" << &a << endl;cout << "交换后:b=" << b << " , &b=" << &b << endl;
}
指针与内存管理
1、 栈上定义的变量不用手动释放,作用域结束就自动回收了
2、堆上定义的变量必须手动delete
掉
分配内存
new
关键字
// 在堆分配一个int
int* p = new int;
*p = 42;
cout << "p= " << p << ", *p=" << *p << endl;
释放内存
delete
关键字
delete p;
// 释放单个对象
delete[] arr;
// 释放数组
// 在堆分配一个int
int* p = new int;
*p = 42;
cout << "p= " << p << ", *p=" << *p << endl;delete p;
p = nullptr;cout << "p= " << p << ", *p=" << *p << endl;
引用
引用定义的时候必须初始化,一经绑定不可修改,
理解为变量的别名
类似指针常量,地址不可变
特性 | 引用(Reference) | 指针(Pointer) |
---|---|---|
本质 | 变量的别名 | 存储地址的变量 |
初始化 | 必须在声明时初始化 | 可以延迟初始化 |
重新绑定 | ❌ 不能重新绑定 | ✅ 可以指向不同对象 |
空值 | ❌ 不存在空引用 | ✅ 可以为空(nullptr ) |
内存占用 | 通常不额外占用(编译器优化) | 占用内存(存储地址) |
操作符 | & (声明时) | & (取地址),* (解引用) |
int a = 10;
int& ref = a;
cout << "step1, a=" << a << ", ref=" << ref << "&a=" << &a << ", &ref=" << &ref << endl;a = 20;
cout << "step2, a=" << a << ", ref=" << ref << "&a=" << &a << ", &ref=" << &ref << endl;ref = 30;
cout << "step3, a=" << a << ", ref=" << ref << "&a=" << &a << ", &ref=" << &ref << endl;
引用作为函数入参
void swap(int& a, int& b) {int temp = a;a = b;b = temp;
}int main()
{int a = 10, b = 20;cout << "交换前,a=" << a << ", b=" << b << endl;swap(a, b);cout << "交换后,a=" << a << ", b=" << b << endl;
}
引用作为函数出参
int& max(int& a, int& b)
{return a > b ? a : b;
}
int main()
{int a = 10, b = 20;cout << "交换前,a=" << a << ", b=" << b << endl;// 返回引用, c与b其实是一个地址int& c = max(a, b);cout << "交换后,a=" << a << ", b=" << b << ", c=" << c << endl;cout << "交换后,&a=" << &a << ", &b=" << &b << ", &c=" << &c << endl;c = 100;cout << "赋值后,a=" << a << ", b=" << b << ", c=" << c << endl;cout << "赋值后,&a=" << &a << ", &b=" << &b << ", &c=" << &c << endl;
}
常量引用
const int &ref = x;
常用于方法入参
不能通过常量引用修改值
可以直接修改原始变量值
int a = 10;
const int& ref = a;cout << "修改前,a=" << a << " ,ref=" << ref << endl;// 不能通过 const 引用修改值
//ref = 20; // 可以,但 ref 的值也变为 100
a = 100;
cout << "修改后,a=" << a << " ,ref=" << ref << endl;
使用引用场景
- 函数入参传递(尤其是大对象)
- 函数出参需要修改
- 避免拷贝、提高性能
void print(const string &str);
使用指针场景
- 可能为空的情况
- 动态内存管理
- 需要重新指向不同对象
- 实现数据结构(链表、树、图等)
- 与 C语言交互(C 语言没有引用)
智能指针
智能指针 | 头文件 | 所有权模型 | 用途 |
---|---|---|---|
std::unique_ptr | <memory> | 独占所有权 | 单个所有者 |
std::shared_ptr | <memory> | 共享所有权 | 多个所有者 |
std::weak_ptr | <memory> | 非拥有引用 | 解决循环引用 |
std::unique_ptr
- 独占所有权:同一时间只能有一个 unique_ptr 指向对象
- 不可复制:但可以移动(Move)
- 自动释放:析构时自动调用 delete
//std::unique_ptr<int[]> p = std::make_unique<int[]>(10);
std::unique_ptr<int> p = std::make_unique<int>(10);
cout << "修改前,p=" << p << " ,*p=" << *p << endl;*p = 100;
cout << "修改后,p=" << p << " ,*p=" << *p << endl;// 不能复制
// auto p1 = p;// 移动后,p变成空指针
auto p1 = std::move(p);
cout << "移动后,p1 = " << p1 << ", *p1 = " << *p1 << endl;
cout << "移动后,p = " << p << ", *p = " << *p << endl;
std::shared_ptr
- 共享所有权:多个 shared_ptr 可以指向同一对象
- 引用计数:内部维护引用计数,计数为0时自动释放
- 可以复制
std::shared_ptr <int> p1 = std::make_shared<int>(10);
cout << "p1:" << p1.use_count() << endl;{// 复制,共享所有权std::shared_ptr <int> p2 = p1;cout << "p1:" << p1.use_count() << endl;cout << "p2:" << p2.use_count() << endl;// 作用域结束,自动释放
}
cout << "p1:" << p1.use_count() << endl;
std::weak_ptr
解决 shared_ptr 的循环引用问题
- 不增加引用计数
- 不拥有对象
- 必须通过 lock() 转换为 shared_ptr 才能访问对象
std::shared_ptr<int> p = std::make_shared<int>(10);
std::weak_ptr<int> wptr = p;// 检查对象是否还存在
if (auto locked = wptr.lock()) {cout << *locked << endl;
}
else {cout << "对象已释放" << endl;
}