C++指针完全指南

指针是C++中最强大但也最容易让人困惑的特性之一。本文将带你从零开始全面理解指针的概念、用法和最佳实践。

目录

  1. 什么是指针?
  2. 指针的基本操作
  3. 指针与数组
  4. 动态内存分配
  5. 指针与函数
  6. 智能指针
  7. 常见错误与调试技巧

什么是指针?

基本概念

指针是一个变量,其值是另一个变量的内存地址。就像现实生活中的地址可以找到具体的房子一样,指针可以找到内存中的数据。

#include <iostream>
using namespace std;

int main() {
    int var = 10;      // 普通整型变量
    int *ptr = &var;   // 指针变量,存储var的地址
    
    cout << "变量var的值: " << var << endl;
    cout << "变量var的地址: " << &var << endl;
    cout << "指针ptr的值: " << ptr << endl;
    cout << "指针ptr指向的值: " << *ptr << endl;
    
    return 0;
}

指针的声明

int *p;        // 指向整型的指针
double *dp;    // 指向双精度浮点数的指针
char *cp;      // 指向字符的指针

指针的基本操作

取地址运算符(&)和解引用运算符(*)

int main() {
    int value = 42;
    int *pointer = &value;  // &获取地址
    
    cout << "直接访问: " << value << endl;
    cout << "通过指针访问: " << *pointer << endl;  // *解引用
    
    // 通过指针修改变量值
    *pointer = 100;
    cout << "修改后的值: " << value << endl;
    
    return 0;
}

指针的算术运算

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr;  // 指向数组第一个元素
    
    cout << "第一个元素: " << *ptr << endl;
    ptr++;  // 移动到下一个元素
    cout << "第二个元素: " << *ptr << endl;
    ptr += 2;  // 向前移动两个元素
    cout << "第四个元素: " << *ptr << endl;
    
    // 指针比较
    int *ptr2 = &arr[3];
    if (ptr == ptr2) {
        cout << "指针指向相同位置" << endl;
    } else {
        cout << "指针指向不同位置" << endl;
    }
    
    return 0;
}

指针与数组

数组名作为指针

int main() {
    int numbers[5] = {1, 2, 3, 4, 5};
    
    // 三种访问数组元素的方式
    cout << "传统数组访问:" << endl;
    for (int i = 0; i < 5; i++) {
        cout << numbers[i] << " ";
    }
    cout << endl;
    
    cout << "指针算术访问:" << endl;
    for (int i = 0; i < 5; i++) {
        cout << *(numbers + i) << " ";
    }
    cout << endl;
    
    cout << "指针变量访问:" << endl;
    int *ptr = numbers;
    for (int i = 0; i < 5; i++) {
        cout << *(ptr++) << " ";
    }
    cout << endl;
    
    return 0;
}

指针数组 vs 数组指针

int main() {
    int a = 1, b = 2, c = 3;
    
    // 指针数组 - 存储指针的数组
    int *ptrArray[3] = {&a, &b, &c};
    
    // 数组指针 - 指向数组的指针
    int arr[3] = {10, 20, 30};
    int (*arrayPtr)[3] = &arr;
    
    cout << "指针数组演示:" << endl;
    for (int i = 0; i < 3; i++) {
        cout << *ptrArray[i] << " ";
    }
    cout << endl;
    
    cout << "数组指针演示:" << endl;
    for (int i = 0; i < 3; i++) {
        cout << (*arrayPtr)[i] << " ";
    }
    cout << endl;
    
    return 0;
}

动态内存分配

new和delete操作符

int main() {
    // 动态分配单个变量
    int *single = new int(42);
    cout << "动态分配的整数: " << *single << endl;
    
    // 动态分配数组
    int size = 5;
    int *array = new int[size];
    
    // 初始化数组
    for (int i = 0; i < size; i++) {
        array[i] = i * 10;
    }
    
    cout << "动态数组内容: ";
    for (int i = 0; i < size; i++) {
        cout << array[i] << " ";
    }
    cout << endl;
    
    // 释放内存
    delete single;
    delete[] array;
    
    return 0;
}

二维数组的动态分配

int main() {
    int rows = 3, cols = 4;
    
    // 分配行指针数组
    int **matrix = new int*[rows];
    
    // 为每一行分配内存
    for (int i = 0; i < rows; i++) {
        matrix[i] = new int[cols];
    }
    
    // 初始化矩阵
    int counter = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = counter++;
        }
    }
    
    // 打印矩阵
    cout << "动态二维数组:" << endl;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << matrix[i][j] << "\t";
        }
        cout << endl;
    }
    
    // 释放内存
    for (int i = 0; i < rows; i++) {
        delete[] matrix[i];
    }
    delete[] matrix;
    
    return 0;
}

指针与函数

指针作为函数参数

// 传值 vs 传指针
void swapByValue(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

void swapByPointer(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5, y = 10;
    
    cout << "交换前: x = " << x << ", y = " << y << endl;
    
    swapByValue(x, y);
    cout << "传值交换后: x = " << x << ", y = " << y << endl;
    
    swapByPointer(&x, &y);
    cout << "传指针交换后: x = " << x << ", y = " << y << endl;
    
    return 0;
}

函数返回指针

// 返回动态分配的内存
int* createArray(int size) {
    int *arr = new int[size];
    for (int i = 0; i < size; i++) {
        arr[i] = i * i;  // 平方数
    }
    return arr;
}

// 危险的返回局部变量地址的例子
int* dangerousFunction() {
    int localVar = 100;
    return &localVar;  // 错误!局部变量在函数结束后销毁
}

int main() {
    int size = 5;
    int *myArray = createArray(size);
    
    cout << "创建的数组: ";
    for (int i = 0; i < size; i++) {
        cout << myArray[i] << " ";
    }
    cout << endl;
    
    delete[] myArray;  // 记得释放内存
    
    return 0;
}

函数指针

#include <iostream>
#include <cmath>
using namespace std;

// 普通函数
double add(double a, double b) {
    return a + b;
}

double multiply(double a, double b) {
    return a * b;
}

// 函数指针作为参数
void calculate(double a, double b, double (*operation)(double, double)) {
    double result = operation(a, b);
    cout << "计算结果: " << result << endl;
}

int main() {
    double x = 5.5, y = 2.5;
    
    // 声明函数指针
    double (*funcPtr)(double, double);
    
    // 指向add函数
    funcPtr = add;
    cout << "加法: " << funcPtr(x, y) << endl;
    
    // 指向multiply函数
    funcPtr = multiply;
    cout << "乘法: " << funcPtr(x, y) << endl;
    
    // 使用函数指针作为参数
    calculate(x, y, add);
    calculate(x, y, multiply);
    calculate(x, y, pow);  // 使用标准库的pow函数
    
    return 0;
}

智能指针

为什么需要智能指针?

传统指针需要手动管理内存,容易导致内存泄漏。智能指针自动管理内存生命周期。

unique_ptr

#include <memory>

void uniquePtrDemo() {
    // 创建unique_ptr
    unique_ptr<int> uptr1 = make_unique<int>(42);
    
    cout << "unique_ptr值: " << *uptr1 << endl;
    
    // unique_ptr不能复制,只能移动
    unique_ptr<int> uptr2 = move(uptr1);
    
    if (uptr1 == nullptr) {
        cout << "uptr1现在为空" << endl;
    }
    
    cout << "uptr2的值: " << *uptr2 << endl;
    
    // 自动释放内存,无需手动delete
}

shared_ptr

#include <memory>

class MyClass {
public:
    MyClass(int val) : value(val) {
        cout << "MyClass构造函数,值: " << value << endl;
    }
    
    ~MyClass() {
        cout << "MyClass析构函数,值: " << value << endl;
    }
    
    void print() {
        cout << "值: " << value << endl;
    }
    
private:
    int value;
};

void sharedPtrDemo() {
    // 创建shared_ptr
    shared_ptr<MyClass> ptr1 = make_shared<MyClass>(100);
    
    {
        shared_ptr<MyClass> ptr2 = ptr1;  // 共享所有权
        cout << "引用计数: " << ptr1.use_count() << endl;
        ptr2->print();
    }
    
    cout << "引用计数: " << ptr1.use_count() << endl;
    ptr1->print();
    
    // 离开作用域时自动释放
}

weak_ptr

#include <memory>

void weakPtrDemo() {
    shared_ptr<int> shared = make_shared<int>(99);
    weak_ptr<int> weak = shared;
    
    cout << "shared引用计数: " << shared.use_count() << endl;
    
    if (auto temp = weak.lock()) {  // 尝试获取shared_ptr
        cout << "weak_ptr的值: " << *temp << endl;
        cout << "临时shared_ptr引用计数: " << temp.use_count() << endl;
    }
    
    shared.reset();  // 释放资源
    
    if (weak.expired()) {
        cout << "资源已被释放" << endl;
    }
}

常见错误与调试技巧

常见指针错误

void commonMistakes() {
    // 1. 未初始化指针
    int *uninitialized;
    // *uninitialized = 5;  // 未定义行为!
    
    // 2. 空指针解引用
    int *nullPtr = nullptr;
    // *nullPtr = 10;  // 程序崩溃!
    
    // 3. 野指针
    int *wildPtr;
    {
        int temp = 15;
        wildPtr = &temp;
    }
    // *wildPtr = 20;  // temp已销毁,未定义行为!
    
    // 4. 内存泄漏
    int *leaked = new int[100];
    // 忘记delete[] leaked;
    
    // 5. 重复释放
    int *doubleDelete = new int(50);
    delete doubleDelete;
    // delete doubleDelete;  // 错误!重复释放
}

调试技巧

#include <cassert>

void debugTechniques() {
    // 1. 使用断言
    int *ptr = new int(25);
    assert(ptr != nullptr);  // 确保指针有效
    cout << "指针值: " << *ptr << endl;
    delete ptr;
    
    // 2. 初始化指针
    int *alwaysInitialize = nullptr;  // 好习惯
    
    // 3. 检查空指针
    if (alwaysInitialize != nullptr) {
        *alwaysInitialize = 30;
    }
    
    // 4. 使用RAII(资源获取即初始化)
    // 优先使用智能指针而不是裸指针
    
    // 5. 内存泄漏检测工具
    // 使用Valgrind、AddressSanitizer等工具
}

最佳实践总结

// 好的指针实践示例
class GoodPractices {
public:
    GoodPractices() : data(make_unique<int[]>(100)) {
        // 使用智能指针自动管理内存
    }
    
    void processData() {
        if (data) {  // 检查指针有效性
            for (int i = 0; i < 100; i++) {
                data[i] = i;
            }
        }
    }
    
private:
    unique_ptr<int[]> data;  // 自动内存管理
};

int main() {
    GoodPractices example;
    example.processData();
    
    // 不需要手动释放内存
    return 0;
}

总结

指针是C++中强大而重要的特性,正确使用指针可以:

  • 实现高效的内存访问
  • 支持动态数据结构
  • 实现多态和回调机制
  • 优化程序性能

记住关键要点:

  1. 理解指针的基本概念(地址和解引用)
  2. 掌握指针算术和数组关系
  3. 正确使用动态内存分配
  4. 优先使用智能指针而不是裸指针
  5. 遵循最佳实践避免常见错误

通过不断练习和理解,指针将成为你C++编程中的有力工具!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐