C/C++内存管理

引言

在c语言中我们开辟数组都是指定空间

int arr[10]={0};//在栈空间上开辟四十个字节
char arry[10]={0};//在栈空间上开辟十个字节

这种开辟空间的缺点:​​​​​

  • 空间开辟大小是固定的
  • 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配

但我们时常不知道空间具体要开多大,只有程序运行的时候才能知道,这时数组编译时开辟空间就不满足,所以这种时候往往需要动态开辟内存来解决

C/C++内存分布

代码段 

  • 存储内容:程序的可执行指令

  • 特性:只读、在程序运行期间不变

  • 包含:机器指令、字符串常量

  • 示例:函数定义、"hello world" 字符串

数据段 

  • 存储内容:已初始化的全局变量和静态变量

  • 特性:在程序开始时就分配,生命周期与程序相同

  • 包含

    • 全局变量(初始化)

    • 静态变量(初始化)

    • 常量(部分)

int global_var = 100;        // 数据段
static int static_var = 200; // 数据段

 BSS 段 

  • 存储内容:未初始化的全局变量和静态变量

  • 特性:在程序开始时自动初始化为0

  • 包含

    • 未初始化全局变量

    • 未初始化静态变量

int uninit_global;           // BSS段
static int uninit_static;    // BSS段

堆 (Heap)

  • 存储内容:动态分配的内存

  • 特性:手动管理(malloc/free, new/delete),向上增长

  • 生命周期:由程序员控制

int *arr = (int*)malloc(100 * sizeof(int)); // 堆内存

栈 (Stack)

  • 存储内容:局部变量、函数参数、返回地址

  • 特性:自动管理,向下增长,LIFO(后进先出)

  • 生命周期:函数调用期间

  • void function() {
        int local_var = 10;      // 栈内存
        char buffer[100];        // 栈内存
    }

    内存特性对比

    区域存储内容管理方式增长方向生命周期
    代码段程序指令系统固定程序运行期
    数据段初始化全局/静态变量系统固定程序运行期
    BSS段未初始化全局/静态变量系统固定程序运行期
    动态分配内存手动向上程序员控制
    局部变量、函数参数自动向下函数调用期
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int data_var = 100;              // 数据段
int bss_var;                     // BSS段
const char* str = "Hello";       // 代码段(字符串在代码段)

void function(int param) {       // 代码段
    int local_var = 10;          // 栈
    static int static_local = 5; // 数据段
    
    char* heap_mem = (char*)malloc(100); // 堆
    strcpy(heap_mem, "Dynamic");
    
    free(heap_mem);              // 需要手动释放
}

int main() {                     // 代码段
    function(20);                // 参数在栈
    return 0;
}

C语言动态内存管理方式

malloc

malloc函数向内存申请一块连续可用的空间,并返回指向这块空间的指针

malloc特性

  • 开辟成功,则返回一个指向开辟好空间的指针
  • 开辟失败,则返回一个NULL指针
  • 返回值的类型是 void*,malloc函数不知道需要开辟什么空间的类型,需要由自己设置
  • 如果参数 size 0malloc的行为是标准是未定义的,取决于编译器
  • 分配的内存块的内容不会初始化,保留不确定值
  • 此函数从不抛出异常

malloc用法

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

realloc

realloc函数相较与malloc函数,动态内存管理更加灵活

realloc特性

  • 重新分配内存块
  • 该函数可以将内存块移动到新位置(其地址由函数返回)
  • 如果是空指针,则该函数的行为类似于 ,分配一个新的字节块并返回指向其开头的指针

realloc用法

int* a=(int*)malloc(sizeof(int));
int* b=(int*)realloc(a,sizeof(int)*10);
realloc在调整内存空间的是存在两种情况
  • 原有空间之后有足够大的空间

要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化

  • 原有空间之后没有足够大的空间
原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址

calloc

函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

calloc用法

int *p = (int*)calloc(10, sizeof(int));

当对申请的内存空间内容要求初始化时,可以用calloc函数

free

free函数用来释放动态开辟的内存

free特性

  • 参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的
  • 如果参数 ptr NULL指针,则函数什么事都不做

free用法

#include <stdlib.h>     /* malloc, calloc, realloc, free */

int main ()
{
  int * buffer1, * buffer2, * buffer3;
  buffer1 = (int*) malloc (100*sizeof(int));
  buffer2 = (int*) calloc (100,sizeof(int));
  buffer3 = (int*) realloc (buffer2,500*sizeof(int));
  free (buffer1);
  free (buffer3);
  return 0;
}

malloc/calloc/realloc三者区别

特性malloccallocrealloc
初始化不初始化初始化为0保持原内容
参数总字节数元素个数 × 元素大小指针 + 新大小
用途一般分配需要零初始化的分配调整已分配内存大小
性能较快稍慢(因为要清零)取决于调整情况

使用注意事项

  • 使用后必须用 free() 释放内存
  • 检查返回值是否为 NULL(分配失败)
  • realloc 传入 NULL 指针时相当于 malloc
  • realloc 传入大小为 0 时相当于 free

C++动态内存管理

new和delete

new开辟一个内存并初始化,delete释放旧内存

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr4 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr5 = new int(10);
  
  // 动态申请10个int类型的空间
  int* ptr6 = new int[10];
  delete ptr4;
  delete ptr5;
  delete[] ptr6;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用 new[]和delete[],匹配起来使用
class A
{
public:
    A(int a=1)
    :_a(a)
    {
        cout<<"A()"<<this<<endl;
    }

    ~A()
    {
        cout<<"~A()"<<this<<endl;
    }
private:
    int _a;
}:

int main()
{
    A* aa1=new A(1);
    delete aa1;
    A* aa2=(A*)malloc(sizeof(A));
    free(aa2);
    
    A* aa3=new A[10];
    delete[] aa3;
    A* aa4=(A*)malloc(sizeof(A)*10);
    free(aa4);
    return 0;
}

malloc没办法支持动态申请空间的自定义对象初始化

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与
free不会
如果申请的是内置类型的空间,new和malloc,delete和free基本类似
不同的地方是: new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL

new的原理

  • 调用operator new函数申请空间
  • 在申请的空间上执行构造函数,完成对象的构造

delete的原理

  • 在空间上执行析构函数,完成对象中资源的清理工作
  • 调用operator delete函数释放对象的空间

new T[N]的原理

  • 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  • 在申请的空间上执行N次构造函数

delete[]的原理

  • 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  • 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

malloc/free和new/delete的区别

基本区别

特性malloc/freenew/delete
语言C 语言库函数C++ 运算符
返回值void* (需要强制转换)正确类型的指针
参数字节数类型
初始化不调用构造函数调用构造函数
清理不调用析构函数调用析构函数
重载不可重载可以重载
异常返回 NULL抛出 std::bad_alloc
大小计算手动计算自动计算

总结

  1. 在 C++ 中优先使用 new/delete,因为它们支持面向对象特性

  2. malloc/free 在 C 中使用,或在需要与 C 代码交互时使用

  3. 不要混用:用 new 分配的内存要用 delete 释放,用 malloc 分配的内存要用 free 释放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值