在C++中,指针(Pointer) 是一个非常核心且强大的概念,它直接操作内存地址,是实现动态内存管理、高效数据结构(如链表、树)、函数参数传递优化等的关键工具。然而,指针也因其复杂性和易错性而“臭名昭著”。下面系统地介绍C++中指针及其关键点。

一、指针的基本概念

指针是一个变量,其值为另一个变量的内存地址。通过指针,你可以间接访问和操作该地址上的数据。
基本语法:


数据类型 *指针名;

示例:


int a = 10;
int *p = &a;  // p 是指向整型变量 a 的指针,&a 是 a 的地址

cout << "a 的值: " << a << endl;      // 输出: 10
cout << "a 的地址: " << &a << endl;   // 输出: 0x7fff... (内存地址)
cout << "p 的值: " << p << endl;      // 输出: 0x7fff... (同上)
cout << "*p 的值: " << *p << endl;    // 输出: 10 (*p 是解引用,访问 p 指向的内容)

二、指针的关键点(核心概念与注意事项)

1. 取地址运算符 &

用于获取变量的内存地址。
例如:int *p = &a; 中的 &a。

2. 解引用运算符 *

用于访问指针所指向的内存地址中的值。
例如:*p = 20; 会将 a 的值修改为 20。
空指针或野指针解引用会导致未定义行为(通常程序崩溃)。

3. 指针的初始化与赋值

必须初始化:未初始化的指针是“野指针”,指向随机内存,解引用极其危险。

    int *p;     // 危险!p 是野指针
    int *q = nullptr; // 推荐:初始化为 nullptr
    int *r = &a;      // 推荐:指向一个有效变量

4. 空指针 nullptr(C++11)

用于表示指针不指向任何对象。
替代旧的 NULL(通常是 0 或 ((void*)0))和直接使用 0。

    int *p = nullptr;
    if (p) { /* 检查指针是否有效 */ }

5. 指针与数组的关系

数组名本质上是一个指向首元素的指针。

    int arr[5] = {1, 2, 3, 4, 5};
    int *p = arr;        // 等价于 &arr[0]
    cout << *p << endl;  // 输出: 1
    cout << *(p+1) << endl; // 输出: 2
指针算术:p + 1 指向下一个元素(地址增加 sizeof(类型) 字节)。

6. 指针与函数

函数参数传递:通过指针可以修改实参的值(类似引用,但更灵活)。
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
int x = 1, y = 2;
swap(&x, &y); // x 和 y 的值被交换

函数返回指针:需谨慎,避免返回局部变量的地址(局部变量在函数结束时销毁)。


    int* func() {
        int local = 10;
        return &local; // 错误!返回局部变量地址,悬空指针
    }

7. 动态内存管理(new 和 delete)

使用 new 在堆上分配内存,返回指向该内存的指针。
使用 delete 释放内存,防止内存泄漏。

    int *p = new int(42);     // 分配一个 int,初始化为 42
    cout << *p << endl;       // 输出: 42
    delete p;                 // 释放内存
    p = nullptr;              // 避免悬空指针

    int *arr = new int[10];   // 分配数组
    delete[] arr;             // 释放数组,注意使用 delete[]

8. 悬空指针(Dangling Pointer)

指向已被释放或销毁的内存的指针。
使用悬空指针是未定义行为。
解决方法:释放内存后立即将指针置为 nullptr。

9. 常量指针与指向常量的指针

指向常量的指针:不能通过指针修改值。
   深色版本

const int *p = &a;  // 或 int const *p
// *p = 20;         // 错误!不能修改
p = &b;             // 可以改变指针指向

常量指针:指针本身不能改变指向。


int *const p = &a;
*p = 20;            // 可以修改 a 的值
// p = &b;          // 错误!不能改变 p 的指向

指向常量的常量指针:


    const int *const p = &a;
    // *p = 20;         // 错误
    // p = &b;          // 错误

10. 多级指针(指针的指针)

指向指针的指针。
    深色版本

    int a = 10;
    int *p = &a;
    int **pp = &p;       // pp 指向 p
    cout << **pp << endl; // 输出: 10

三、指针的常见错误与陷阱

错误	后果	预防
未初始化指针(野指针)	随机内存访问,崩溃或数据损坏	始终初始化为 nullptr
解引用空指针	程序崩溃(段错误)	使用前检查 if (p != nullptr)
解引用悬空指针	未定义行为	delete 后置 nullptr
内存泄漏	程序占用内存不断增加	new 和 delete 成对出现
数组越界访问	覆盖其他内存,安全漏洞	检查索引范围
delete 与 delete[] 混用	未定义行为	数组用 delete[],单个对象用 delete

四、现代C++中的指针使用建议

虽然指针功能强大,但现代C++更推荐使用更安全的替代方案:

优先使用引用(&):当不需要重新绑定且不为 nullptr 时。
使用智能指针(C++11):
    std::unique_ptr<T>:独占所有权,自动释放。
    std::shared_ptr<T>:共享所有权,引用计数。
    std::weak_ptr<T>:解决循环引用。

    #include <memory>
    auto p = std::make_unique<int>(42);
    // 无需手动 delete,离开作用域自动释放

    使用容器:如 std::vector、std::array 替代原始数组。
    使用 std::string:替代字符指针。

总结

关键点	说明
本质	存储内存地址的变量
核心操作	&(取地址),*(解引用)
安全性	易出错,需谨慎管理
现代替代	引用、智能指针、容器
最佳实践	初始化、检查空、及时释放、优先使用智能指针
指针是C++的“双刃剑”:掌握它,你将能写出高效、灵活的代码;滥用它,则可能导致难以调试的错误。在现代C++中,应尽量使用RAII和智能指针来管理资源,将指针的使用限制在必要场景。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐