世界杯2022是哪个国家_国足世界杯出线 - dtfyjq.com

  • 首页
  • 北京世界杯
  • 世界杯新秀
  • 世界杯16强名单

最新发表

  • 没尾巴的狗常见品种有哪些,没尾巴的狗品种和名字
  • 我为什么喜欢《PREY》的一切
  • 曾志伟十大电影排行榜 曾志伟演过的经典电影介绍
  • 上海探秘:揭秘本地热门的“找鸡”好去处
  • pt管理软件有哪些
  • 亡灵生物
  • 私货的解释
  • 梦幻西游花果山攻略大全2025
  • 结婚送日子帖子怎么写?男方家给女方送日子必须要知道这些规矩!否则让人笑话
  • 文曲星 - 电子词典

友情链接

Copyright © 2022 世界杯2022是哪个国家_国足世界杯出线 - dtfyjq.com All Rights Reserved.

C++ 指针进阶:动态分配内存

世界杯新秀 · 2025-10-29 05:42:20

C++ 动态实例化(new 和 malloc)

malloc / free

工作原理

malloc 是 stdlib.h 库中的函数,原型为 void *__cdecl malloc(size_t _Size);:

作用:

malloc 函数沿空闲链表(位于内存 堆空间 中)申请一块满足需求的内存块,将所需大小的内存块分配给用户剩下的返回到链表上;

并返回指向该内存区的首地址的指针,意该指针的类型为 void *,因此我们需要强制转换指针类型;

参数:_Size 表示所需分配内存的字节数;即需要显式填入申请内存的大小,如 n * sizeof(int);

返回值:

malloc 返回一个指向分配内存的指针;如果分配失败,则 NULL 指针,可以通过返回值判断是否分配成功;

返回指针的类型为 void*,需要显示类型转换;

malloc 并不会初始化所申请的空间。

free 也是 stdlib.h 库中的函数,原型为 void __cdecl free(void *_Memory);:

作用:free 函数会将用户释放的内存块连接到空闲链上;

参数:指针 _Memory 应指向由 malloc(), calloc(), realloc() 分配的内存块,其他方式声明的内存不能用 free();

free 函数的实参 ptr 必须指向内存块的首地址(即 malloc 的返回值),否则可能导致错误;

动态分配的内存需要手动释放,否则可能导致内存泄漏;

调用 free(ptr) 后,并不会改变 ptr 的值,但是最好将指针设置为 NULL 以避免悬空指针问题。

具体使用

动态创建一维数组

size_t element_cnt = 10;

int *arr = (int *)malloc(element_cnt * sizeof(int));

/* ... */

free(arr)

动态创建二维数组

size_t m = 10, n = 10;

int **arr = (int **)malloc(m * sizeof(int *));

for (int i = 0; i < m; i ++)

arr[i] = (int *)malloc(n * sizeof(int));

需要注意,这样获得的二维数组,不能保证其空间是连续的。但是可以通过 arr[i][j] 的方式访问元素 (i, j).

释放二维数组时需要一个逆向操作:

for (int i = 0; i < m; i ++)

free(arr[i]);

free(arr);

calloc

calloc 定义在 stdlib.h 库中,声明为 void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements);

calloc 与 malloc 的主要区别有:

作用:

calloc 函数用于在程序运行时分配一块指定数量和大小的内存,并将每个字节的内容初始化为零;

参数:

NumOfElements 为要分配的元素个数;

_SizeOfElements 为每个元素的大小(以字节为单位);

返回值:

返回值方式与 malloc 相同;

由于初始化分配内存的原因,calloc 的运行效率要低于 malloc。

realloc

realloc 定义在 stdlib.h 库中,声明为 void *__cdecl realloc(void *_Memory,size_t _NewSize);,用于对动态内存块进行扩大或缩小:

原理:如果原内存块后有足够的连续空间,则会直接扩大原内存块;否则将数据拷贝到新分配的内存空间,并释放元内存块(自动释放,不需要 free);

参数:

_Memory 为 指向之前分配内存块的指针;

_NewSize 为 调整后的内存块的字节数;

返回值:

如果 _Memory 后有足够的连续空间,则直接扩大原内存块,并返回 _Memory;

如果空间不够,则返回指向重新分配的内存块的指针;

如果重新分配失败且 ptr 不为 NULL,则返回 NULL,并且原来的内存块保持不变;

若 _NewSize 小于原大小,原数据末尾可能会丢失;

如果 _Memory 为空,则 realloc 相当于 malloc。

new / delete

工作原理

new 和 delete 是 C++ 中的关键字,若要使用,需要编译器支持。

工作原理:

new 首先会分配所需大小的内存,并调用对象的构造函数来初始化对象;对于数组,new 会分配足够的内存来容纳整个数组,并返回数组的首地址;

delete 会调用对象的析构函数进行清理工作,然后释放对象占用的内存;对于数组,delete[] 会正确的释放整个数组所占用的内存,并对数组中的每个函数调用析构函数;

返回值:

内存分配成功时,new 返回对象类型的指针,类型严格与对象匹配;

new 内存分配失败时,会抛出 bac_alloc 异常,如果不捕捉异常,那么程序就会异常退出;

new 无需显式填入申请的内存大小,new 会根据 new 的类型分配内存;

new 分配的内存空间在 自由存储区;

new 和 delete 支持 重载;

不能对一块内存释放两次或以上;

但对空指针 nullptr 使用 delete 操作是合法的;

使用 new 分配内存后,必须使用 delete 释放内存,否则可能导致内存泄漏;

不要对非 new 分配的内存使用 delete,也不要对 new 分配的内存使用 free。

具体应用

动态实例化

// 动态创建变量

int *p = new int(1234);

/* ... */

delete p;

new 动态创建对象时会经历三个步骤:

调用 operator new 函数分配一块足够的内存空间(通常底层默认使用 malloc 实现)以存储特定类型的对象;

编译器运行相应的构造函数以构造函数,并为其传入初值;

返回一个指向该对象的指针;

delete 释放对象内存时会经历两个步骤:

调用对象的析构函数;

编译器调用 operator delete 函数释放内存空间(通常底层默认使用 free 实现);

// 开辟新的对象

class A {

int a;

public:

A(int a_) : a(a_) {}

};

int main() {

A *p = new A(1234);

/* ... */

delete p;

}

{} 运算符可以用来初始化没有构造函数的结构。初次以外,使用 {} 运算符可以使得变量的初始化形式变得统一。

struct ThreeInt {

int a;

int b;

int c;

};

int main() {

ThreeInt* p = new ThreeInt{1, 2, 3};

/* ... */

delete p;

}

动态创建数组

创建和释放数组需要使用 new[] 和 delete[],new[] 运算符会返回数组的首地址。

size_t element_cnt = 5;

int *p = new int[element_cnt];

/* ... */

delete[] p;

动态创建二维数组有以下三种方式:

声明一个长度为 N * M 的一维数组,通过下标 r * M + c 访问二维数组中小标为 (r, c) 的元素:

int *arr = new int[N * M];

这种方法可以保证二维数组的物理空间是 连续的。

通过变量存储 数组的数组 的首地址——指向一个一维数组的指针的地址。这个变量即 二级指针:

int **arr = new int*[M];

for (int i = 0; i < M; i ++)

a[i] = new int[N];

需要注意,这样获得的二维数组,不能保证其空间是连续的。

对于这样获得的内存的释放,需要进行一个逆向操作:释放每一个一维数组,再释放存储一维数组首地址的地址:

for (int i = 0; i < M; i ++)

delete[] arr[i];

delete[] arr;

第三种方法用到 指向数组的指针:

int (*arr)[N] = new int[M][N];

/* ... */

delete[] arr;

这种方式得到的也是连续的内存,但与第一种方式相比,可以直接使用 arr[n] 的形式得到数组第 n + 1 行的首地址,使用 arr[r][c] 的形式访问到下标为 (r, c) 的元素。

由于指向数组的指针也是一种确定的数据类型,因此除数组的第一维外,其他维度的长度均须为一个能在编译器确定的常量。

malloc 和 new 的主要区别

特征

new / delete

malloc / free

分配内存的位置

自由存储区

堆

内存分配失败

抛出异常 bac_alloc

返回 NULL

分配内存大小

编译器根据类型计算得出

显式指定字节数

处理数组

new[]

人为计算数组大小后进行内存分配

已分配内存的扩张

不支持

realloc

分配时内存不足

可以指定处理函数或重新指定分配器

无法通过用户代码处理

是否可以重载

可以

不可以

构造和析构函数

调用

不调用


你真会判断DataGuard的延迟吗?
如何查看谷歌地图,教你几招