当前位置: 首页 > news >正文

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

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

// #include

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

【补充:】此时我在听别人面试
为什么排序可以提高效率?
排序后可以减少比较次数。

相关文章:

  • 33、Java 异常掌握这些就够了(图解 Java 中的异常)
  • springboot-方法处理4-消息转换器
  • FPGA底层资源综述
  • CLIP扩展
  • 从一维卷积、因果卷积(Causal CNN)、扩展卷积(Dilation CNN) 到 时间卷积网络 (TCN)
  • 高等数学(第七版)同济大学 习题8-2 个人解答
  • [HJ56 完全数计算]
  • 【nlp】天池学习赛-新闻文本分类-机器学习
  • 机器人系统,如何快速算法开发与原型机验证?
  • 调用静态方法
  • Vue的生命周期详解
  • 机器人控制算法九之机器人建模(XML)、工作场景Scances建模(VRML)
  • 【Unity3D日常开发】Unity3D中打包WEBGL后读取本地文件数据
  • 【SDS V6 专题】开放内容平台,XOCP 助力数据常青
  • 鲜花绿植学生网页设计模板 静态HTML鲜花学生网页作业成品 DIV CSS网上鲜花植物主题静态网页
  • [译] React v16.8: 含有Hooks的版本
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 77. Combinations
  • JavaScript DOM 10 - 滚动
  • Meteor的表单提交:Form
  • mysql innodb 索引使用指南
  • ng6--错误信息小结(持续更新)
  • php中curl和soap方式请求服务超时问题
  • Redis 懒删除(lazy free)简史
  • vue--为什么data属性必须是一个函数
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 第十八天-企业应用架构模式-基本模式
  • 构造函数(constructor)与原型链(prototype)关系
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 中文输入法与React文本输入框的问题与解决方案
  • 阿里云服务器如何修改远程端口?
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • #AngularJS#$sce.trustAsResourceUrl
  • #Z0458. 树的中心2
  • #微信小程序:微信小程序常见的配置传旨
  • (23)Linux的软硬连接
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .“空心村”成因分析及解决对策122344
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .NET/C# 使窗口永不获得焦点
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • ??javascript里的变量问题
  • @cacheable 是否缓存成功_Spring Cache缓存注解
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • [ C++ ] 继承
  • [android] 看博客学习hashCode()和equals()
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)