Appearance
指针
指针是C++最重要也是最具特色的概念之一。指针允许直接操作内存地址,是C++强大功能的核心。本章将详细介绍指针的概念和使用方法。
指针基础
指针的定义和使用
cpp
#include <iostream>
using namespace std;
int main() {
// ============ 指针基础 ============
int num = 10;
// & 取地址运算符:获取变量的内存地址
cout << "num的值: " << num << endl;
cout << "num的地址: " << &num << endl;
// 定义指针:类型* 指针名
int* ptr; // 定义一个int类型的指针
ptr = # // ptr指向num
// 定义并初始化
int* ptr2 = #
// * 解引用运算符:获取指针指向的值
cout << "\nptr指向的地址: " << ptr << endl;
cout << "ptr指向的值: " << *ptr << endl;
// 通过指针修改值
*ptr = 20;
cout << "修改后num的值: " << num << endl;
// ============ 指针的类型 ============
int i = 10;
double d = 3.14;
char c = 'A';
int* intPtr = &i; // int指针
double* doublePtr = &d; // double指针
char* charPtr = &c; // char指针
cout << "\n各类型指针:" << endl;
cout << "int指针: " << intPtr << ", 值: " << *intPtr << endl;
cout << "double指针: " << doublePtr << ", 值: " << *doublePtr << endl;
cout << "char指针: " << (void*)charPtr << ", 值: " << *charPtr << endl;
// ============ 空指针 ============
// C风格空指针
int* nullPtr1 = NULL;
// C++风格空指针(推荐)
int* nullPtr2 = nullptr;
// 检查空指针
if (nullPtr2 == nullptr) {
cout << "\n这是一个空指针" << endl;
}
// 解引用空指针是危险的!
// *nullPtr2 = 10; // 错误:段错误
return 0;
}指针运算
cpp
#include <iostream>
using namespace std;
int main() {
// ============ 指针算术运算 ============
int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr; // 数组名就是首元素的地址
cout << "===== 指针算术运算 =====" << endl;
// 指针加整数
cout << "*ptr = " << *ptr << endl; // 10
cout << "*(ptr + 1) = " << *(ptr + 1) << endl; // 20
cout << "*(ptr + 2) = " << *(ptr + 2) << endl; // 30
// 指针自增
ptr++;
cout << "\nptr++后: *ptr = " << *ptr << endl; // 20
ptr++;
cout << "ptr++后: *ptr = " << *ptr << endl; // 30
// 指针减整数
cout << "*(ptr - 1) = " << *(ptr - 1) << endl; // 20
// 指针相减(得到元素个数)
int* start = arr;
int* end = arr + 5;
cout << "\n指针相减: " << end - start << endl; // 5
// 指针比较
cout << "start < end: " << (start < end) << endl; // true
// ============ 指针与数组 ============
cout << "\n===== 指针与数组 =====" << endl;
int numbers[] = {1, 2, 3, 4, 5};
int* p = numbers;
// 两种等价的访问方式
for (int i = 0; i < 5; i++) {
cout << "numbers[" << i << "] = " << numbers[i];
cout << ", *(p + " << i << ") = " << *(p + i) << endl;
}
// 使用指针遍历
cout << "\n使用指针遍历: ";
for (int* q = numbers; q < numbers + 5; q++) {
cout << *q << " ";
}
cout << endl;
// ============ 不同类型的指针步长 ============
cout << "\n===== 指针步长 =====" << endl;
int intArr[5] = {1, 2, 3, 4, 5};
double doubleArr[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
int* ip = intArr;
double* dp = doubleArr;
cout << "int指针步长:" << endl;
for (int i = 0; i < 5; i++) {
cout << "地址: " << (ip + i) << ", 值: " << *(ip + i) << endl;
}
cout << "\ndouble指针步长:" << endl;
for (int i = 0; i < 5; i++) {
cout << "地址: " << (dp + i) << ", 值: " << *(dp + i) << endl;
}
return 0;
}指针与const
cpp
#include <iostream>
using namespace std;
int main() {
// ============ const与指针的组合 ============
int value = 10;
int another = 20;
// 1. 指向常量的指针(底层const)
// 不能通过指针修改值,但可以改变指针指向
const int* ptr1 = &value;
cout << "指向常量的指针:" << endl;
cout << "*ptr1 = " << *ptr1 << endl;
// *ptr1 = 30; // 错误:不能修改指向的值
ptr1 = &another; // 正确:可以改变指向
cout << "改变指向后 *ptr1 = " << *ptr1 << endl;
// 2. 常量指针(顶层const)
// 不能改变指针指向,但可以修改值
int* const ptr2 = &value;
cout << "\n常量指针:" << endl;
cout << "*ptr2 = " << *ptr2 << endl;
*ptr2 = 30; // 正确:可以修改值
cout << "修改值后 *ptr2 = " << *ptr2 << endl;
// ptr2 = &another; // 错误:不能改变指向
// 3. 指向常量的常量指针
// 既不能修改值,也不能改变指向
const int* const ptr3 = &value;
cout << "\n指向常量的常量指针:" << endl;
cout << "*ptr3 = " << *ptr3 << endl;
// *ptr3 = 40; // 错误:不能修改值
// ptr3 = &another; // 错误:不能改变指向
// ============ 记忆技巧 ============
/*
* 记忆技巧:从右往左读
*
* const int* p -> p is a pointer to const int
* (p是指向常量int的指针)
*
* int* const p -> p is a const pointer to int
* (p是指向int的常量指针)
*
* const int* const p -> p is a const pointer to const int
* (p是指向常量int的常量指针)
*/
return 0;
}引用
cpp
#include <iostream>
using namespace std;
int main() {
// ============ 引用基础 ============
int num = 10;
// 引用:变量的别名
// 定义时必须初始化,之后不能改变引用的对象
int& ref = num; // ref是num的引用
cout << "num = " << num << endl;
cout << "ref = " << ref << endl;
cout << "&num = " << &num << endl;
cout << "&ref = " << &ref << endl; // 地址相同
// 通过引用修改值
ref = 20;
cout << "\n修改ref后 num = " << num << endl;
// 通过变量修改值
num = 30;
cout << "修改num后 ref = " << ref << endl;
// ============ 引用与指针的区别 ============
cout << "\n===== 引用与指针的区别 =====" << endl;
int a = 10, b = 20;
// 指针
int* ptr = &a;
cout << "指针指向a: *ptr = " << *ptr << endl;
ptr = &b; // 可以改变指向
cout << "指针指向b: *ptr = " << *ptr << endl;
// 引用
int& ref2 = a;
cout << "引用绑定a: ref2 = " << ref2 << endl;
ref2 = b; // 这不是改变引用,而是赋值!
cout << "赋值b: a = " << a << endl; // a变成了20
// ============ 引用的特点 ============
// 1. 必须初始化
// int& r; // 错误:引用必须初始化
// 2. 一旦绑定不能改变
int x = 10, y = 20;
int& r = x;
r = y; // 这是赋值,不是改变引用
cout << "\nx = " << x << endl; // x = 20
// 3. 没有空引用
// int& nullRef = nullptr; // 错误
// 4. 没有引用的引用
// int&& refRef = r; // 这是右值引用,不是引用的引用
// ============ 常量引用 ============
const int& constRef = 100; // 可以绑定到字面量
cout << "\nconstRef = " << constRef << endl;
// constRef = 200; // 错误:不能修改
// 常量引用可以绑定到不同类型(会创建临时变量)
const double& dRef = 10; // int -> double
cout << "dRef = " << dRef << endl;
return 0;
}智能指针
cpp
#include <iostream>
#include <memory> // 智能指针头文件
using namespace std;
// 测试类
class Resource {
public:
string name;
Resource(string n) : name(n) {
cout << "创建资源: " << name << endl;
}
~Resource() {
cout << "销毁资源: " << name << endl;
}
void use() {
cout << "使用资源: " << name << endl;
}
};
int main() {
// ============ unique_ptr ============
cout << "===== unique_ptr =====" << endl;
// 独占所有权的智能指针
// 不能复制,只能移动
// 创建方式1
unique_ptr<Resource> ptr1(new Resource("资源1"));
// 创建方式2(推荐)
auto ptr2 = make_unique<Resource>("资源2");
// 使用
ptr1->use();
ptr2->use();
// 获取原始指针
Resource* raw = ptr1.get();
cout << "原始指针: " << raw->name << endl;
// 移动所有权
unique_ptr<Resource> ptr3 = move(ptr1);
// ptr1现在是nullptr
if (ptr1 == nullptr) {
cout << "ptr1已转移所有权" << endl;
}
// 释放所有权
Resource* released = ptr3.release();
cout << "释放后需要手动删除" << endl;
delete released;
// ============ shared_ptr ============
cout << "\n===== shared_ptr =====" << endl;
// 共享所有权的智能指针
// 引用计数,最后一个指针销毁时释放资源
// 创建
auto sptr1 = make_shared<Resource>("共享资源");
cout << "引用计数: " << sptr1.use_count() << endl; // 1
{
// 复制(增加引用计数)
shared_ptr<Resource> sptr2 = sptr1;
cout << "引用计数: " << sptr1.use_count() << endl; // 2
shared_ptr<Resource> sptr3 = sptr1;
cout << "引用计数: " << sptr1.use_count() << endl; // 3
sptr2->use();
} // sptr2, sptr3离开作用域
cout << "引用计数: " << sptr1.use_count() << endl; // 1
sptr1->use();
// 离开作用域时自动销毁
// ============ weak_ptr ============
cout << "\n===== weak_ptr =====" << endl;
// 弱引用,不增加引用计数
// 用于解决shared_ptr的循环引用问题
auto shared = make_shared<Resource>("弱引用资源");
weak_ptr<Resource> weak = shared;
cout << "shared引用计数: " << shared.use_count() << endl; // 1
cout << "weak引用计数: " << weak.use_count() << endl; // 1(不影响)
// 使用weak_ptr需要lock()
if (auto locked = weak.lock()) {
locked->use(); // 成功获取
}
shared.reset(); // 释放资源
// 检查是否过期
if (weak.expired()) {
cout << "资源已释放" << endl;
}
if (auto locked = weak.lock()) {
locked->use();
} else {
cout << "无法获取资源" << endl;
}
// ============ 智能指针选择 ============
/*
* 智能指针选择建议:
*
* 1. unique_ptr:
* - 独占资源所有权
* - 性能最好,无额外开销
* - 默认选择
*
* 2. shared_ptr:
* - 需要共享所有权时使用
* - 有引用计数开销
*
* 3. weak_ptr:
* - 打破shared_ptr循环引用
* - 观察者模式
* - 缓存实现
*/
return 0;
}指针与函数
cpp
#include <iostream>
#include <memory>
using namespace std;
// ============ 指针作为参数 ============
// 通过指针修改值
void doubleValue(int* ptr) {
if (ptr != nullptr) {
*ptr *= 2;
}
}
// 通过指针交换两个值
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// ============ 引用作为参数 ============
// 通过引用修改值(更简洁)
void doubleValueRef(int& ref) {
ref *= 2;
}
// 通过引用交换
void swapRef(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
// ============ 返回指针 ============
// 返回局部变量的指针(危险!)
// int* badReturn() {
// int local = 10;
// return &local; // 错误:返回局部变量的地址
// }
// 返回动态分配的内存
int* createArray(int size) {
return new int[size]; // 调用者需要delete[]
}
// 返回智能指针(推荐)
unique_ptr<int[]> createArraySmart(int size) {
return make_unique<int[]>(size);
}
// 返回静态变量的指针
int* getStaticValue() {
static int value = 0;
value++;
return &value; // 静态变量生命周期是整个程序
}
int main() {
// 指针作为参数
int num = 10;
cout << "修改前: " << num << endl;
doubleValue(&num);
cout << "修改后: " << num << endl;
// 交换
int a = 5, b = 10;
cout << "\n交换前: a = " << a << ", b = " << b << endl;
swap(&a, &b);
cout << "交换后: a = " << a << ", b = " << b << endl;
// 引用作为参数
num = 10;
cout << "\n引用修改前: " << num << endl;
doubleValueRef(num);
cout << "引用修改后: " << num << endl;
a = 5, b = 10;
cout << "\n引用交换前: a = " << a << ", b = " << b << endl;
swapRef(a, b);
cout << "引用交换后: a = " << a << ", b = " << b << endl;
// 返回指针
int* arr = createArray(5);
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
cout << "\n动态数组: ";
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
cout << endl;
delete[] arr;
// 智能指针
auto smartArr = createArraySmart(5);
for (int i = 0; i < 5; i++) {
smartArr[i] = i + 1;
}
cout << "智能指针数组: ";
for (int i = 0; i < 5; i++) {
cout << smartArr[i] << " ";
}
cout << endl;
// 自动释放
// 静态变量指针
cout << "\n静态变量: ";
for (int i = 0; i < 3; i++) {
int* p = getStaticValue();
cout << *p << " ";
}
cout << endl;
return 0;
}本章小结
本章学习了:
- 指针基础:定义、初始化、解引用
- 指针运算:加减运算、指针与数组
- const与指针:指向常量的指针、常量指针
- 引用:引用的定义和特点
- 智能指针:unique_ptr、shared_ptr、weak_ptr
- 指针与函数:指针参数、返回指针
下一章,我们将学习字符串,了解C++字符串的处理方法。
