动态内存分配

动态内存分配

常见的程序崩溃的原因:
  • 由assert()触发的;
  • 操作内存时,越界了;
  • 内存没有被初始化就拿去用了;
  • 栈溢出了;
  • 使用了野指针。

总之,非法操作内存会对引起程序崩溃。

C中动态内存管理方式:

使用malloc/calloc/realloc/free进行动态内存管理。

malloc、calloc、realloc的相同点与不同点:

相同点:

  • 都是在堆上开辟空间的。
  • 都是通过free来释放空间的。
  • 返回值:成功都是void*,失败都是NULL。

不同点:(体现在每个函数的功能和参数列表不同

  • malloc只负责把空间开辟出来。malloc(字节数)
  • calloc(单个元素所占字节数的大小,需要的元素个数)
  • realloc对空间进行扩增和缩减。
realloc(地址, 新开辟空间的大小);
//如果新的大小大于原内存大小,则新分配不会被初始化;
// 如果新的大小小于原内存大小,则可能会导致部分数据丢失

面试题:什么是内存泄露?如何检测一个系统是否存在内存泄露?
答:内存泄漏是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

常见的内存泄露:
void MemoryLeaks()
{
    //1.内存申请了,忘了释放
    int *pstr = (int*)malloc(sizeof(int));
    assert(pstr);

    //2.逻辑不清,以为自己释放了,实际造成了内存泄露
    int *p1 = (int*)malloc(sizeof(int));
    int *p2 = (int*)malloc(sizeof(int));
    p1 = p2;//p1指向p2的空间,p1原来指向的空间就找不到了,此时p1和p2指向同一块空间
    free(p1);//p1将p2指向的空间释放了
    free(p2);//p2又来释放,导致同一块空间释放多次

    //3.溢出,将堆破坏了
    char *pstr = (char*)malloc(5);//只开辟了5个空间
    strcpy(pstr, "hello word!!!");//strcpy不会进行类型检测
    free(pstr);

    //4.释放时传入的地址和申请时的地址不相同
    int *p = (int*)malloc(sizeof(int));
    p++;
    free(p);

}
C++内存管理方式:

C语言内存管理方式在C++中可以继续使用,但尽量使用自己的内存管理方式:

C++中通过new和delete运算符进行动态内存管理

void TestNewDelete()
{
    int* p1 = new int;//申请单个空间(4个字节)
    //delete p1;

    int* p2 = new int(10);//申请单个空间(4个字节)并将其初始化为10
    //delete p2;

    int* p3 = new int[10];//申请了10个一段连续的空间(40个字节)
    //delete[] p3;

    delete p1;
    delete p2;
    delete[] p3;
}
int main()
{
    TestNewDelete();
    return 0;
}

C语言动态申请内存空间须注意

  • 申请后要对其进行判空。
  • 要传入想要申请的字节数。
  • 若要接受开辟的这段空间,必须对其进行类型转化。

然而C++不需要注意这些。

注意
1. new和delete是运算符,而不是函数;但malloc / calloc / realloc / free都是函数
2. new和delete、new和delete[]一定要匹配使用!!!否则会出现内存泄露甚至程序发生崩溃。

malloc / free 和 new /delete 比较

一、测试malloc和free、new和delete、new和delete[]都没有匹配起来时:

void Test()
{
    int *p1 = (int*)malloc(sizeof(int));
    int *p2 = (int*)malloc(sizeof(int));

    int *p3 = new int;
    int *p4 = new int;

    int *p5 = new int[10];
    int *p6 = new int[10];

    delete p1;
    delete[] p2;

    free(p3);
    delete[] p4;

    free(p5);
    delete p6;
}
int main()
{
    Test();
    return 0;
}
上述代码能通过编译,也能正常运行,不存在内存泄露

构造Test类,再来测试以下代码:
class Test
{
public:
    Test()
    {
        cout << "Test:" << this << endl;
    }

    /*~Test()
    {
        cout << "~Test:" << this << endl;
    }*/
};
void main()
{
    Test *p1 = (Test*)malloc(sizeof(Test));
    Test *p2 = (Test*)malloc(sizeof(Test));
    delete p1;//此处会打印出析构函数体的内容,即此处调用了析构函数
    delete[] p2;//程序发生崩溃,如果将析构函数屏蔽掉,则不会发生崩溃

    Test *p3 = new Test;//此处会打印出构造函数体的内容,即此处调用了构造函数
    Test *p4 = new Test;//此处会打印出构造函数体的内容,即此处调用了构造函数
    free(p3);
    delete[] p4;//程序发生崩溃

    Test *p5 = new Test[10];//此处调用了10次构造函数
    Test *p6 = new Test[10];//此处调用了10次构造函数
    free(p5);//程序发生崩溃
    delete p6;

}

二、malloc / free 和 new / delete 的区别和联系?

  • 它们都是动态管理内存的入口函数。
  • malloc / free 是C/C++标准库的函数,new / delete 是C++操作符。
  • malloc / free 只是动态分配内存空间 / 释放空间。而 new / delete 除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员)。
  • malloc 后跟字节数;new 后跟申请空间的类型。
  • malloc 申请空间失败后,返回NULL;new 申请空间失败后,会调用_callnewh 或直接抛系统异常。
  • malloc 申请空间时一定要判空,而new不需要;。
  • 申请单个空间时,new 会对其初始化;而 malloc 不会。
  • malloc 一定是在堆上开辟空间;而new不一定。
  • malloc / free 需要手动计算类型大小且返回值为 void*;new / delete 可自己计算类型的大小,返回对应类型的指针。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值