C/C++ 内存申请和释放

1. malloc & free

malloc


基本用法
// MSDN 推荐使用方法
// C++ 不支持 void* 向其他类型的隐式转换,需进行强制类型转换,
// C 支持 void* 向其他类型的隐式转换,可不进行强制类型转换
int* n = (int*)malloc(sizeof(int));
if (n == NULL) {
  // 进行内存申请失败的错误处理
} else {
  // 进行正常操作
  free(n);
}
动态申请数组

申请一个有 6 个整形数组元素的一维数组,申请完不能初始化(代码如下),只能通过 memset() 或循环的方式赋值

int* p = (int*)malloc(sizeof(int) * 6);

因该操作程序运行到这条语句时才在堆区申请的数组,所以被称为动态申请内存(数组),栈区的数组在编译时就已经申请好内存了,所以不是动态申请的

动态申请数组指针
int (*p)[3] = (int(*)[3])malloc(sizeof(int) * 3); // 一维数组指针
int (*q)[2][3] = (int(*)[2][3])malloc(sizeof(int) * 6); // 二维数组指针
初始化
void* memset(void* dest, int c, size_t count);
void* memcpy(void* dest, void* src, size_t count);

free


int* p = (int*)malloc(4);
free(p);
p = NULL; // 释放后要置为空指针
int* q = (int*)malloc(3);
free(q); // 会报错,int 型指针一次操作 4Byte,这里只申请了 3Byte 相当去别人的地盘上拆东西,那肯定是不允许的
int* n = (int*)malloc(7); // 允许多申请,但是 intv型指针一次只能操作 4Byte 多余的空间浪费了
free(n); // 释放时,从 OS 维护的表中查找到空间长度,会一并释放掉

注意

int* p = (int*)malloc(sizeof(int));

if (p == NULL) { // p 是空指针
    // 空间申请失败的错误处理
} else {
    // 申请成功,假设 p == 0X00000191D34DDAB0;
    free(p); // p == 0X00000191D34DDAB0;
             // p有值,但是指向的内存空间已经被释放掉了,p 就成了一个野指针了
    p = NULL; // 释放空间后,指针需要置空,避免成为野指针
}

int *p; //这种,定义完指针未初始化,也是野指针

2. new & delete

new


基本用法
int* p = new int;     // 申请单个空间
int* q = new int[10]; // 申请连续空间
new 的探究
// 这是 VC\Tools\MSVC\14.16.27023\crt\src\vcruntime\new_scalar.cpp 中的代码
// 可以看到 new 的底层还是 malloc

_CRT_SECURITYCRITICAL_ATTRIBUTE
void* __CRTDECL operator new(size_t const size)
{
    for (;;)
    {
        if (void* const block = malloc(size))
        {
            return block;
        }

        if (_callnewh(size) == 0)
        {
            if (size == SIZE_MAX)
            {
                __scrt_throw_std_bad_array_new_length();
            }
            else
            {
                __scrt_throw_std_bad_alloc();
            }
        }
        // The new handler was successful; try to allocate again...
    }
}

delete


基本用法
delete p;
delete[] q;
delete 的探究

3. 其他申请内存的方式

  1. calloc
void* calloc(size_t num, size_t size);

申请连续的 num 块内存,每块内存的字节数为 size;并将这些字节置为初始化为 0,返回值为所申请空间的首地址,申请数组时比较方便,但是效率可能比 malloc() 会慢一点,因为多了一步初始化操作

  1. realloc
void* realloc(void* memblock, size_t size); // 为已分配的内存空间重新申请内存块
  1. _msize
size_t _msize(void* memblock);  // Windows平台下专用函数,非C语言标准函数

返回 malloc() & calloc() & realloc() 等申请内存块的大小,参数是分配内存块的首地址,也就是 malloc() & calloc() & realloc() 等的返回值

int* p = (int*)malloc(sizeof(int));
int pSize = _msize(p);  // pSize == 4;
int* q = (int*)realloc(p, sizeof(int) * 2);
int qSize = _msize(q);  // qSize == 8; p 和 q 可能相等也可能不相等
Table of Contents