C++ 指针及内存模型

C++ 指针及内存管理

1. 指针的基本概念

  • 指针定义:指针是一个变量,用于存储另一个变量的内存地址。

  • 基本语法

  • int* ptr; // 声明一个指向整数的指针

  • 指针初始化:指针必须指向有效的内存地址。int a = 10;

  • int* ptr = &a; // ptr 指向 a 的地址

  • 指针解引用:使用 * 操作符可以访问指针指向的值。

  • std::cout << *ptr; // 输出 10

2. 指针的使用

  • 访问变量

  • int a = 5;
    int* ptr = &a; // ptr 指向 a
    *ptr = 10; // 修改 a 的值为 10
    std::cout << a; // 输出 10

  • 指针运算

  • 指针可以进行加减操作,用于遍历数组。
  • int arr[] = {1, 2, 3};
    int* p = arr; // p 指向 arr 的首元素
    std::cout << *(p + 1); // 输出 2

3. 指针作为函数参数

  • 通过指针传递参数:可以修改调用者提供的数据。
  • void increment(int* ptr) {
        (*ptr)++; // 修改指针指向的值
    }

    int main() {
        int value = 5;
        increment(&value); // 传递 value 的地址
        std::cout << value; // 输出 6
    }

4. const 修饰指针

  • const int* ptr (指向常量的指针)

    这意味着指针指向的数据是常量,不能通过该指针修改指向的值,但指针本身是可以改变指向其他地址的。

  • int a = 5, b = 10;
    const int* ptr = &a; // ptr 指向 a,不能通过 ptr 修改 a 的值
    ptr = &b; // 合法,指针可以指向 b,但仍不能通过 ptr 修改 b 的值
    //*ptr = 20; // 错误,不能通过 ptr 修改 *ptr 的值

  • int* const ptr (常量指针)

    这里的含义是,指针本身是常量,指针一旦指向某个地址,不能再改变它指向其他地址,但可以修改指向的值。

  • int a = 5, b = 10;
    int* const ptr = &a; // ptr 是常量指针,不能指向其他地址
    *ptr = 20; // 合法,可以修改 a 的值为 20
    //ptr = &b; // 错误,不能修改 ptr 指向的地址

  • const int* const ptr (指向常量的常量指针)

    这里既不能修改指针指向的地址,也不能修改指针指向的数据。这是最严格的一种声明。

  • int a = 5, b = 10;
    const int* const ptr = &a; // ptr 是常量指针,指向的值也是常量
    //*ptr = 20; // 错误,不能通过 ptr 修改 a 的值
    //ptr = &b; // 错误,不能修改 ptr 指向的地址

5. void 关键字

  • 定义:表示没有类型,常用于函数的返回类型。

  • 示例

  • void doNothing() {
        // 什么也不做
    }

  • 指向 void 的指针:可以指向任何类型,但需转换。

  • void* ptr;
    int a = 5;
    ptr = &a; // ptr 指向整型数据
    int* intPtr = (int*)ptr; // 强制转换
    std::cout << *intPtr; // 输出 5

6. C++ 内存模型

C++ 内存主要分为以下几个区域:

6.1 栈(Stack)
  • 管理方式:后进先出(LIFO),自动分配和释放。
  • 用途:存储局部变量和函数调用的参数。
  • 特点
    • 分配速度快。
    • 存储大小有限,超出可能导致栈溢出。
    • void function() {
          int localVar = 5; // 存储在栈中
      } // localVar 在函数返回时自动释放
6.2 堆(Heap)
  • 管理方式:手动分配和释放。
  • 用途:动态内存分配,用于不确定大小的数据结构。
  • 特点
    • 灵活性高,内存大小不受限制。
    • 分配和释放速度较慢,容易导致内存泄漏。
  • void function() {
        int* ptr = new int; // 在堆中分配内存
        *ptr = 20; // 赋值
        delete ptr; // 释放内存
    }
6.3 全局/静态存储区
  • 用途:存储全局变量和静态变量。
  • 特点:从程序开始到结束一直存在,自动管理。
  • int globalVar = 100; // 存储在全局存储区

    void function() {
        static int staticVar = 10; // 存储在全局存储区
    }

6.4 代码区(Code Segment)
  • 用途:存储程序的可执行代码,通常只读。
  • 特点:程序加载时分配。
  • void function() {
        // 执行代码
    }
     
6.5 内存模型示意图

+-------------------+
|    代码区         |
|   (Code Segment)  |
+-------------------+
|    全局/静态区    |
|   (Global/Static) |
+-------------------+
|        堆         |
|      (Heap)       |
|                   |
|                   |
+-------------------+
|        栈         |
|      (Stack)      |
+-------------------+

7. 动态分配内存 newdelete

  • new 操作符:在堆中分配内存。

  • 单个变量分配

  • int* ptr = new int; // 分配一个整数
    *ptr = 10; // 赋值

  • 数组分配

  • int* arr = new int[5]; // 分配一个整数数组
    for (int i = 0; i < 5; i++) {
        arr[i] = i; // 初始化
    }

  • delete 操作符:释放内存。

  • 单个变量释放

  • delete ptr; // 释放内存
    ptr = nullptr; // 避免悬空指针
     

  • 数组释放

  • delete[] arr; // 释放动态分配的数组

8. 空指针和野指针

  • 空指针
    • 定义:空指针指向无效的内存地址,通常用 nullptrNULL 表示。
    • 用途:指示指针不指向有效内存。
    • int* ptr = nullptr; // 指针未初始化
      if (ptr) {
          // 不会进入此分支
      }
  • 野指针
  • 定义:指向已释放内存或未初始化的指针。
  • 原因:释放内存后指针仍然指向原地址,或者未初始化。
  • int* ptr = new int(10);
    delete ptr; // 释放内存
    // ptr 现在是野指针
    std::cout << *ptr; // 未定义行为

9. 函数指针和回调函数

  • 函数指针:指向函数的指针,可以用来调用函数或将函数作为参数传递。

  • 声明和使用

  • void func(int x) {
        std::cout << "Value: " << x << std::endl;
    }

    void (*funcPtr)(int) = &func; // 定义函数指针
    funcPtr(5); // 调用函数

  • 回调函数:通过函数指针传递的函数,用于在某些事件发生时被调用。

  • 示例

  • void execute(void (*callback)(int)) {
        callback(10); // 调用传入的回调函数
    }

    int main() {
        execute(func); // 传递 func 函数作为回调
    }

  • 10. 智能指针

    C++11 引入智能指针以自动管理内存,减少内存泄漏和错误:

  • std::unique_ptr:独占所有权,不能复制,只能移动。

  • #include <memory>

    void function() {
        std::unique_ptr<int> ptr(new int(5)); // 动态分配内存
        std::cout << *ptr; // 使用智能指针
    } // 超出作用域时自动释放内存

  • std::shared_ptr:共享所有权,可以多个指针指向同一内存。

  • #include <memory>

    void function() {
        std::shared_ptr<int> ptr1(new int(5));
        std::shared_ptr<int> ptr2 = ptr1; // ptr2 共享 ptr1 的所有权
    } // 当所有指向同一内存的指针都超出作用域时,内存被释放

  • std::weak_ptr:不控制内存的生命周期,避免循环引用。

  • #include <memory>

    void function() {
        std::shared_ptr<int> ptr1(new int(5));
        std::weak_ptr<int> weakPtr = ptr1; // weakPtr 不增加引用计数
    } // 当 ptr1 超出作用域时,weakPtr 不会阻止内存释放

11. 总结

  • 指针是 C++ 中强大的工具,提供了直接内存访问的能力。
  • 正确使用指针和内存管理机制(如 newdelete、智能指针)是确保程序安全和高效的关键。
  • 理解指针的基本概念、内存管理、函数指针和智能指针是编写健壮 C++ 代码的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值