C++进阶——指针

第一部分:指针的本质(内存视角)

  1. 内存地址的物理意义
  • 计算机内存是一系列连续编址的存储单元
  • 每个变量占据特定内存区域(如int x占4字节)
  • 地址:内存单元的唯一编号(如0x7ffeeb0c)
  1. 指针的定义
cppint x = 42;       // 普通变量
int* ptr = &x;    // ptr保存x的地址
  • &操作符:取地址操作符(Address-of Operator)
  • *操作符:声明指针类型或解引用操作符(Dereference Operator)
  1. 内存可视化
| 变量名 | 地址    ||
|--------|---------|-------|
| x      | 0x1000  | 42    |
| ptr    | 0x1004  | 0x1000|

第二部分:指针操作深度解析

  1. 基本操作
int y = *ptr;     // 解引用:y = 42
*ptr = 100;       // 修改x的值为100
  1. 指针算术
int arr[3] = {10, 20, 30};
int* p = arr;     // p指向arr[0]
p++;              // 移动sizeof(int)字节(通常4字节)
cout << *p;       // 输出20
  • 关键规则:指针加减以指向类型的大小为单位
  1. 指针与数组的关系
int* p1 = &arr[0]; // 等价于p1 = arr
int* p2 = arr + 2; // 指向arr[2]

第三部分:多级指针与高级类型

  1. 二级指针(Pointer to Pointer)
int x = 42;
int* p = &x;
int** pp = &p;    // pp指向指针p
cout << **pp;     // 输出42

2.结构体与指针

struct Point { int x; int y; };
Point pt = {3, 4};
Point* p = &pt;
cout << p->x;      // 等价于(*p).x

3.函数指针

int add(int a, int b) { return a + b; }
int (*funcPtr)(int, int) = &add;
cout << funcPtr(2, 3); // 输出5

第四部分:动态内存管理

  1. 堆内存分配
int* ptr = new int;    // 分配1个int
int* arr = new int[5]; // 分配数组
delete ptr;            // 释放单个对象
delete[] arr;          // 释放数组
  1. 常见内存错误

悬空指针(Dangling Pointer)
内存泄漏(Memory Leak)
重复释放(Double Free)

  1. 智能指针(C++11+)
#include 
std::unique_ptr<int> uPtr(new int(42)); // 独占所有权
std::shared_ptr<int> sPtr = std::make_shared<int>(100); // 共享所有权

第五部分:高级应用场景

  1. 多态与虚函数表(vptr)
class Animal {
public:
    virtual void speak() = 0; // 虚函数表指针存在对象头部
};
  1. 内存映射与底层操作
char* buffer = (char*)malloc(1024); // 原始内存操作
// 使用reinterpret_cast处理二进制数据
  1. 指针与性能优化
  • 避免数据拷贝(传递指针而非对象)
  • 缓存友好访问(连续内存访问)

第六部分:调试与工具

  1. 调试技巧
  • 使用cout打印指针地址
  • 内存调试工具(Valgrind, AddressSanitizer)
  1. 常见面试问题
  • 指针与引用的区别
  • const int* vs int* const
  • 如何检测内存泄漏?

练习题目

  1. 实现链表数据结构
  2. 编写函数交换两个变量的值(使用指针)
void swap(int& a,int& b){
	int t = a;
	a = b;
	b = t;
}
  1. 分析以下代码的错误:
int* createInt() {
    int x = 10;
    return &x; // 返回局部变量地址
}

这段代码存在严重的**悬空指针(Dangling Pointer)**问题,具体分析如下:

错误原因

  1. 局部变量的生命周期
  • 变量x在函数createInt()内部定义,是局部变量。
  • 局部变量存储在栈内存中,其生命周期仅限于函数作用域内。
  • 当函数createInt()执行完毕返回时,栈内存会被释放,x的地址失效。
  1. 返回无效地址
  • return &x;返回了指向已释放内存的地址。
  • 调用者获得的指针指向的内存已被回收,成为悬空指针。

未定义行为(Undefined Behavior)
以下操作均会导致不可预测的结果:

int* p = createInt();
cout << *p;  // 可能崩溃或输出随机值
*p = 20;     // 可能破坏其他数据

图解内存变化

  1. 函数执行期间:
| 栈内存       ||
|-------------|------|
| x (地址0x100)| 10   |
  1. 函数返回后:
| 栈内存       ||
|-------------|------|
| (地址0x100)  | 垃圾数据 |

修正方法
方法1:动态内存分配(堆内存)

int* createInt() {
    int* x = new int(10);  // 在堆上分配内存
    return x;              // 需手动delete释放
}

// 调用方必须delete
int* p = createInt();
cout << *p;  // 合法
delete p;    // 必须释放!

方法2:返回静态变量(慎用!)

int* createInt() {
    static int x = 10;  // 静态变量,生命周期持续到程序结束
    return &x;          // 合法但有风险(非线程安全)
}

方法3:智能指针(C++11+推荐)

#include 
std::unique_ptr<int> createInt() {
    return std::make_unique<int>(10); // 自动管理内存
}

// 调用方无需手动释放
auto p = createInt();
cout << *p;  // 合法

方法4:直接返回值(最安全)

int createInt() {
    return 10;  // 不涉及指针
}

int x = createInt(); // 安全可靠

关键总结

错误类型 风险 修正方案
返回局部变量地址 产生悬空指针,导致未定义行为(崩溃/数据错误) 1. 动态内存分配new + 手动delete
2. 静态变量static int x(慎用)
3. 智能指针std::unique_ptr(推荐)
4. 返回值:直接返回int而非指针

修正方案对比

方案 优点 缺点
动态内存分配 (new) 明确控制生命周期 需手动管理内存,易泄漏
静态变量 (static) 生命周期持续到程序结束 非线程安全,多调用共享同一内存
智能指针 自动内存管理,安全可靠 需C++11+支持
直接返回值 无内存管理问题,最简单安全 仅适用于简单数据类型,无法返回复杂对象

你可能感兴趣的:(C++进阶,c++,开发语言)