C++内存管理

关于堆和栈的知识点:

  1. 堆的空间较大,有几个G,其它区都是MB
  2. 堆向上使用空间,栈向下使用空间
  3. 每个程序运行起来都有4G虚拟内存,都是按需申请和释放。
    所以堆一般不可能达4G
  • 例题:
  1. 下面有关c++内存分配堆栈说法错误的是( ):
    A.对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制
    B. 对于栈来讲,生长方向是向下的,也就是向着内存地址减小的方向;对于堆来讲,它的生长方向是向上的,是向着内存地址增加的方向增长
    C.对于堆来讲,频繁的 new/delete 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题
    D.一般来讲在 32 位系统下,堆内存可以达到4G的空间,但是对于栈来讲,一般都是有一定的空间大小的
  • 分析:
    D:因为32位下,程序使用内存最大4G,不可能都给堆。所以堆达不到4G。

    1. C++中关于堆和栈的说法,哪个是错误的:( )

A.堆的大小仅受操作系统的限制,栈的大小一般较小
B.在堆上频繁的调用new/delete容易产生内存碎片,栈没有这个问题
C.堆和栈都可以静态分配
D.堆和栈都可以动态分配

解析:

  1. 栈既可以自动分配也可以手动动态分配,但是栈分配到的不能用free或delete释放。所以D正确,堆栈都可以动态分配。
  2. 堆只能手动动态分配,不能静态分配。
  3. 堆上频繁用new、delete容易产生碎片,栈因为自动分配,所以不存在此问题。

变量内存区判断:
4. char* pchar3 = “abcd”;
指针指向常量字符串的地址,该指针是常量指针,有的编译器会强调加const,因为指向内容不能改变。
char char2[] = “abcd”
这个char2[] 数组,char2代表数组首地址,而char2代表的是字母a,
因为char char2[] = “abcd”左边是字符数组,字符数组都在栈上开辟,而char3是指针,右边是常量,所以两者不一样。
int
ptr1 = ()malloc(),这种ptr1是临时变量,在栈,它只是指向了堆区。
而*ptr1,解引用,变为它存的地址上放置的值

sizeof:对数字数组,总共几个数字共占的大小
对字符数组,大小方面,会多一个\0结束符
strlen:专为字符串和字符数组,结果是 字母个数

再次注意:
char char2 = “abcd”
char*pchar3 = “abcd”
这两个典型的一个在栈上,一个在堆上,前者因为字符数组是临时变量,后者因为是常量。

C++动态内存管理
int* a = new int[5]
intb = new int(5)
第一行开辟5个int空间
第二行带初始化。
A
p4 = new A【5】
A会自动初始化。
delete和free的区别。
delete自动调用析构。
而free之后,还得手动置0,或NULL
对于自定义类型调用析构,而内置类型不管。

资源清理:delete

delete:它自动调用析构。
【回忆:】析构函数不需要手动调用,编译器自己决定。
单纯delete解决不了自己开辟的空间归还问题。

class Test
{
private:
    int* a;
public:
    Test()
    {
         a=new int(0);//需要析构函数来delete,单纯delete Test是无法回收a内存的,直接内存泄漏
     }
};

free和delete不要混着用。
new和delete应该匹配:注意括号
new就用delete
如果我使用 :A* p = new A[5]
最后要用:delete[] p;
C++要new有两个原因:

  1. 定义出来的对象,就一定要初始化。【就是给值】
  2. 抛出异常:面向对象的语言处理错误的方式一般是抛异常,且C++中求报错抛出异常
      面向过程的语言处理错误的方式是:错误码
    C的malloc还有什么问题:
    有时候正常用也可能报错:malloc向堆申请空间,堆虽然很大,但是终究有限,所以还是会有错的可能。
    而C++中new失败了会直接报错,不会返回。
    可以通过捕捉错误,去输出查看是什么类型错误。比起C方便,不用做检查。
    delete和free一般不会失败,如果失败都是释放空间存在越界或释放指针位置不对。
  • 例题:
  1. 下面有关c++内存分配堆栈说法错误的是( )
    A.对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制
    B. 对于栈来讲,生长方向是向下的,也就是向着内存地址减小的方向;对于堆来讲,它的生长方向是向上的,是向着内存地址增加的方向增长
    C.对于堆来讲,频繁的 new/delete 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题
    D.一般来讲在 32 位系统下,堆内存可以达到4G的空间,但是对于栈来讲,一般都是有一定的空间大小的
    1. 例题:
      c++语言中,类ClassA的构造函数和析构函数的执行次数分别为( )
ClassA *pclassa=new ClassA[5];
delete pclassa;
  • 解析:
  1. 开辟对象数组大小为几,就调用几次构造函数。
  2. 这是个对象数组,本该用delete[] pclassa;
    而delete会调用一次析构,**且delete一般不是先free,先调用析构函数。**往往会引发程序崩溃。
    new出来的对象数组,如果delete会直接崩掉。
  • 析构的顺序为:
设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为? ( )
C c;
void main()
{
  A*pa=new A();
  B b;
  static D d;
  delete pa;
}

ABDC.【因为A手动执行delete,最早调用析构。】
C和D都在静态区,应按照栈顺序,A在堆上,B在临时栈区,应该最早销毁,最早用析构。
我本来疑问: new申请的空间,什么时候调用析构。
属实眼瞎了,人家下面对new出来的pa做了delete,所以delete pa先调用A的析构函数。如下图,C是全局变量,D是静态局部遍历,两者C先定义后是D,销毁按栈特点,先D析构再C析构。因为delete,所以A先做析构。析构和构造顺序相反。
CBD的构造顺序是:C、D、B,所以最后析构:B、D、C。
请添加图片描述
析构顺序完全和构造顺序相反,根据栈特点理解。
上面先构造了全局对象,再构造了局部静态对象,最后构造普通对象。其中。
4. 使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?( )
A.会有内存泄露
B.不会有内存泄露,但不建议用
C.编译就会报错,必须使用delete []p
D.编译没问题,运行会直接崩溃

这个题显然是new和delete不按匹配使用。

  1. A。 char是内置类型,对于内置类型delete和free作用一样,不会造成内存泄漏。
  2. 但是这里毕竟带[],所以建议成对。
  1. 以下代码中,A 的构造函数和析构函数分别执行了几次: ( )
    A*pa=new A[10];
    delete []pa;

申请空间不调用构造函数,构造函数调用次数是数组的大小。

例题

请添加图片描述
其中,strlen()统计的是字符数量,不统计\0,但是pChar3、char2右值都是常量,它们都以\0结尾。但是char2是个字符数组,且pChar3也是个指针变量,都在栈区存着,sizeof指针,它只求指针大小,所以必然是4,而sizeof字符数组,肯定带着\0

operator new和operator delete

operator new、operator delete是new和delete的底层,其中operator new实际通过malloc()来申请空间,但不调用构造函数。operator delete通过free()来释放。它俩是对malloc和free的封装。总之,为了失败时抛出异常错误。使得C++符合面向对象处理错误。
而new除了申请空间,还会调用构造函数。
此外,还有 new [],如:Stack* p1 = new class_name[10]; 底层是operator new[],这个封装了operator new。

手动调用构造函数

  • 前言:new会自动申请和调用类的构造函数(类的私有成员不能直接去操作),而当我们在C++想使用malloc()和构造函数去创建类的对象时该怎么办?
      答:使用operator new。

malloc/free、new/delete的区别

请添加图片描述

什么是内存泄漏?它的危害是什么?

  答:动态申请的内存不需要使用了,也没有释放,存在内存泄漏。但是内存不一定有危害。程序虽然运行过程中,可能会有内存泄漏,但是进程正常结束后,会自动把内存释放还给系统。但是在长期运行的程序,出现内存泄漏,危害很大,系统会越来越慢甚至宕机

【回忆:乱码原因】
【随机值字符串编码正好是某个汉字,所以会看见乱码】

【回忆输出格式】:
//记住:补充位数和补充值的方法,且用头文件:

// #include

// cout << year <<“-” <<setw(2)<<setfill(‘0’) << month << “-” <<setw(2) << setfill(‘0’) << day << endl;

【面试】
为什么排序可以提高效率?
排序后可以减少比较次数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值