动态内存分配(C++)

什么叫动态分配?

形象来说,动态分配就像是在一个大型购物广场中,你根据需要随时租用或归还一个店铺。程序运行时,如果需要更多空间来存储数据,就会向操作系统 “租用” 内存空间;用完后,为了避免浪费资源,需要 “归还” 这些空间。这个过程不是自动的,需要你手动管理。

动态分配的优点

  • 灵活性:需要的时候用,不需要的时候还;

    动态分配最核心的地方就是它可以在不需要的时候归还。比如,在某个函数中定义了一个数组 a[5],当这个数组满了之后我们需要对其扩容,if (数组满) a扩容到10,如果这个数组是动态分配的,我们就可以手动的释放之前的 a[5];如果这个数组是静态分配的,这个空间无法释放,会一直占用,直到程序运行结束。

  • 不会占用栈和数据段的空间,为内存减轻负荷;
  • 举例:动态定义的顺序表 \(\text{vs}\) 静态定义的顺序表、动态实现的链表 \(\text{vs}\) 静态实现的链表;

    链表需要进行频繁的插入和删除,如果使用的静态分配,那么这些插入删除的空间在程序运行时将无法释放,只有使用动态分配才有办法在程序运行时释放这些空间,因为静态分配不提供释放空间的方法。

动态分配的语法解释

动态分配的变量

int a = 10;     // 静态分配一个整型
int *b = new int(10);   // 动态分配一个整型

delete b;

这两条语句的功能类似,都得到了一个值为 \(10\) 的变量,只不过变量 a 存储在栈内存中,b 存储在堆内存中;在程序运行时,a 会一直占用这个空间,无法主动释放,b 可以主动释放。

为什么要主动释放?如果我们静态实现了一个链表,每次插入的时候需要分配一个新结点,由于是静态分配的,这个新结点将存在栈内存中;每次删除的时候,虽然链表在逻辑上将其删除了,但是它还是占用着栈空间的;在多次的插入和删除后,将会导致栈溢出,从而发生段错误;使用动态分配就不会这样了,它不仅可以手动释放空间,还不会占用栈内存。

  • 使用 new 关键字进行动态分配时,它总是返回一个指针,指向新分配的内存地址,因为 new 的本质就是申请一份空间;
  • 有借有还,申请了空间,必须手动释放;
  • 访问的时候和指针一样,如果访问内容需要使用 *a

动态分配的数组

int staticArray[5] = {1, 2, 3, 4, 5};   // 静态分配一个整型数组
int *dynamicArray = new int[5]; // 动态分配一个整型数组

delete[] dynamicArray;          // 释放动态分配的整型数组
  • 动态分配数组在 new 的时候使用的是 [元素个数],动态分配变量在 new 的时候使用的是 (元素值)
  • 不能直接利用列表赋值,通常用 for 循环遍历赋值;
  • 访问时与数组类似,又两种访问方式,第一种是利用指针,比如 *(p+1),第二种直接使用数组下标 p[1]。感觉和数组相同;

动态分配的结构体

struct Person {
    string name;
    int age;
};

Person alice = {"Alice", 20};   // 静态分配并初始化一个结构体

Person *Mike = new Person{"Mike", 30};  // 动态分配并初始化一个结构体
delete Mike;

参考

  • 零壹考研
posted @ 2024-06-22 21:43  TimeLimitExceeded  阅读(144)  评论(0)    收藏  举报