基础知识学习---牛客网C++面试宝典(二)C/C++基础之C++内存

news2024/11/26 10:37:48

1、本栏用来记录社招找工作过程中的内容,包括基础知识学习以及面试问题的记录等,以便于后续个人回顾学习; 暂时只有2023年3月份,第一次社招找工作的过程;

2、个人经历: 研究生期间课题是SLAM在无人机上的应用,有接触SLAM、Linux、ROS、C/C++、DJI OSDK等;
3、参加工作后(2021-2023年)岗位是嵌入式软件开发,主要是服务器开发,Linux、C/C++、网络编程、docker容器、CMake、makefile、Shell脚本、JSON等。

4、求职岗位是嵌入式软件开发、C/C++开发、自动驾驶岗位开发等。

在这里插入图片描述

此系列为在学习牛客网C++面试宝典过程中记录的笔记,本篇记录第一章C/C++基础部分的第二节:C++内存。

牛客网C++面试宝典链接:https://www.nowcoder.com/issue/tutorial?tutorialId=93&uuid=8f38bec08f974de192275e5366d8ae24

文章目录

  • 2.1 简述一下堆和栈的区别
  • 2.2 简述C++的内存管理
    • 1、内存分配方式:
    • 2、常见的内存错误及其对策:
    • 3、内存泄露及解决办法:
  • 2.3 malloc和局部变量分配在堆还是栈?
  • 2.4 程序有哪些section,分别的作用?程序启动的过程?怎么判断数据分配在栈上还是堆上?
  • 2.5 初始化为0的全局变量在bss还是data
  • 2.6 什么是内存泄露,内存泄露怎么检测?
  • 2.7 请简述一下atomoic内存顺序。
  • 2.9 简述C++中内存对齐的使用场景
    • 1、什么是内存对齐?
    • 2、为什么要字节对齐?
    • 3、字节对齐实例

2.1 简述一下堆和栈的区别

参考回答

区别:

1、堆栈空间分配不同。栈由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等;堆一般由程序员分配释放。

2、堆栈缓存方式不同。栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立即释放;堆则是存放在二级缓存中,速度要慢些。

3、堆栈数据结构不同。堆类似数组结构;栈类似栈结构,先进后出。

2.2 简述C++的内存管理

参考回答

1、内存分配方式:

在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。

,就是那些由new分配的内存块,一般一个new就要对应一个delete。

自由存储区,就是那些由malloc等分配的内存块,和堆是十分相似的,不过是用free来结束自己的生命。

全局/静态存储区,全局变量和静态变量被分配到同一块内存中

常量存储区,这是一块比较特殊的存储区,里面存放的是常量,不允许修改。

2、常见的内存错误及其对策:

(1)内存分配未成功,却使用了它。

(2)内存分配虽然成功,但是尚未初始化就引用它。

(3)内存分配成功并且已经初始化,但操作越过了内存的边界。

(4)忘记了释放内存,造成内存泄露。

(5)释放了内存却继续使用它。

对策:

(1)定义指针时,先初始化为NULL。

(2)用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。

(3)不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。

(4)避免数字或指针的下标越界,特别要当心发生“多1”或者“少1”操作

(5)动态内存的申请与释放必须配对,防止内存泄漏

(6)用free或delete释放了内存之后,立即将指针设置为NULL,防止“野指针”

(7)使用智能指针。

3、内存泄露及解决办法:

什么是内存泄露?

简单地说就是申请了一块内存空间,使用完毕后没有释放掉。(1)new和malloc申请资源使用后,没有用delete和free释放;(2)子类继承父类时,父类析构函数不是虚函数。(3)Windows句柄资源使用后没有释放。

怎么检测?

第一:良好的编码习惯,使用了内存分配的函数,一旦使用完毕,要记得使用其相应的函数释放掉。

第二:将分配的内存的指针以链表的形式自行管理,使用完毕之后从链表中删除,程序结束时可检查改链表。

第三:使用智能指针。

第四:一些常见的工具插件,如ccmalloc、Dmalloc、Leaky、Valgrind等等。

2.3 malloc和局部变量分配在堆还是栈?

参考回答

malloc是在堆上分配内存,需要程序员自己回收内存;局部变量是在栈中分配内存,超过作用域就自动回收。

2.4 程序有哪些section,分别的作用?程序启动的过程?怎么判断数据分配在栈上还是堆上?

参考回答

请添加图片描述
一个程序有哪些section

如上图,从低地址到高地址,一个程序由代码段数据段BSS段共享区等组成。

1、数据段:存放程序中已初始化的全局变量和静态变量的一块内存区域。

2、代码段:存放程序执行代码的一块内存区域。只读,代码段的头部还会包含一些只读的常数变量。

3、BSS 段:存放程序中未初始化的全局变量和静态变量的一块内存区域。

4、可执行程序在运行时又会多出两个区域:堆区和栈区。

堆区:动态申请内存用。堆从低地址向高地址增长。

栈区:存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。

5、最后还有一个共享区,位于堆和栈之间。

程序启动的过程

1、操作系统首先创建相应的进程并分配私有的进程空间,然后操作系统的加载器负责把可执行文件的数据段和代码段映射到进程的虚拟内存空间中。

2、加载器读入可执行程序的导入符号表,根据这些符号表可以查找出该可执行程序的所有依赖的动态链接库。

3、加载器针对该程序的每一个动态链接库调用LoadLibrary (1)查找对应的动态库文件,加载器为该动态链接库确定一个合适的基地址。 (2)加载器读取该动态链接库的导入符号表和导出符号表,比较应用程序要求的导入符号是否匹配该库的导出符号。 (3)针对该库的导入符号表,查找对应的依赖的动态链接库,如有跳转,则跳到3 (4)调用该动态链接库的初始化函数

4、初始化应用程序的全局变量,对于全局对象自动调用构造函数。

5、进入应用程序入口点函数开始执行。

怎么判断数据分配在栈上还是堆上:首先局部变量分配在栈上;而通过malloc和new申请的空间是在堆上。

2.5 初始化为0的全局变量在bss还是data

参考回答

BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0。

2.6 什么是内存泄露,内存泄露怎么检测?

参考回答

什么是内存泄露?

简单地说就是申请了一块内存空间,使用完毕后没有释放掉。(1)new和malloc申请资源使用后,没有用delete和free释放;(2)子类继承父类时,父类析构函数不是虚函数。(3)Windows句柄资源使用后没有释放。

怎么检测?

第一:良好的编码习惯,使用了内存分配的函数,一旦使用完毕,要记得使用其相应的函数释放掉。

第二:将分配的内存的指针以链表的形式自行管理,使用完毕之后从链表中删除,程序结束时可检查改链表。

第三:使用智能指针。

第四:一些常见的工具插件,如ccmalloc、Dmalloc、Leaky、Valgrind等等。

2.7 请简述一下atomoic内存顺序。

参考回答

有六个内存顺序选项可应用于对原子类型的操作:

1、memory_order_relaxed:在原子类型上的操作以自由序列执行,没有任何同步关系,仅对此操作要求原子性。

2、memory_order_consume:memory_order_consume只会对其标识的对象保证该对象存储先行于那些需要加载该对象的操作。

3、memory_order_acquire:使用memory_order_acquire的原子操作,当前线程的读写操作都不能重排到此操作之前。

4、memory_order_release:使用memory_order_release的原子操作,当前线程的读写操作都不能重排到此操作之后。

5、memory_order_acq_rel:memory_order_acq_rel在此内存顺序的读-改-写操作既是获得加载又是释放操作。没有操作能够从此操作之后被重排到此操作之前,也没有操作能够从此操作之前被重排到此操作之后。

6、memory_order_seq_cst:memory_order_seq_cst比std::memory_order_acq_rel更为严格。memory_order_seq_cst不仅是一个"获取释放"内存顺序,它还会对所有拥有此标签的内存操作建立一个单独全序。

除非你为特定的操作指定一个顺序选项,否则内存顺序选项对于所有原子类型默认都是memory_order_seq_cst。

2.9 简述C++中内存对齐的使用场景

参考回答

内存对齐应用于三种数据类型中:struct/class/union

struct/class/union内存对齐原则有四个:

1、数据成员对齐规则:结构(struct)或联合(union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小的整数倍开始。

2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储。(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储)。

3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的"最宽基本类型成员"的整数倍。不足的要补齐。(基本类型不包括struct/class/uinon)。

4、sizeof(union),以结构里面size最大元素为union的size,因为在某一时刻,union只有一个成员真正存储于该地址。

答案解析

1、什么是内存对齐?

那么什么是字节对齐?在C语言中,结构体是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构体、联合体等)的数据单元。在结构体中,编译器为结构体的每个成员按其自然边界(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构体的地址相同。

为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,**即所谓的“对齐”,比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除,**也即“对齐”跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。

比如在32位cpu下,假设一个整型变量的地址为0x00000004(为4的倍数),那它就是自然对齐的,而如果其地址为0x00000002(非4的倍数)则是非对齐的。现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

2、为什么要字节对齐?

需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。

而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误,而在x86上就不会出现错误,只是效率下降。

各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。

3、字节对齐实例

union example 
{    
	int a[5];    
	char b;    
	double c;   
};  
int result = sizeof(example); 
 /* 如果以最长20字节为准,内部double占8字节,这段内存的地址0x00000020并不是double的整数倍,只有当最小为0x00000024时可以满足整除double(8Byte)同时又可以容纳int a[5]的大小,所以正确的结果应该是result=24 */ 
   
 struct example 
 {    
 int a[5];    
 char b;    
 double c;   
 }test_struct;
 int result = sizeof(test_struct); 
   /* 如果我们不考虑字节对齐,那么内存地址0x0021不是double(8Byte)的整数倍,所以需要字节对齐,那么此时满足是double(8Byte)的整数倍的最小整数是0x0024,说明此时char b对齐int扩充了三个字节。所以最后的结果是result=32 */ 
   
 struct example 
 {    
 char b;    
 double c;    
 int a;   
 }test_struct;   
 int result = sizeof(test_struct);  
  /* 字节对齐除了内存起始地址要是数据类型的整数倍以外,还要满足一个条件,那就是占用的内存空间大小需要是结构体中占用最大内存空间的类型的整数倍,所以20不是double(8Byte)的整数倍,我们还要扩充四个字节,最后的结果是result=24 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/643673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解深度学习——注意力机制(Attention Mechanism):带掩码的多头注意力(Masked Multi-head Attention)

分类目录:《深入理解深度学习》总目录 相关文章: 注意力机制(AttentionMechanism):基础知识 注意力机制(AttentionMechanism):注意力汇聚与Nadaraya-Watson核回归 注意力机制&#…

想了解会计软件吗?来看看Zoho Books的功能和特点

Zoho Books 是一款功能强大的在线会计软件,为企业提供多合一解决方案,该解决方案可定制、可扩展,并使始终保持合规。 轻松生成电子发票 在Zoho Books中,您可以通过包含电子发票架构中提到的所有必填字段来创建电子发票格式的发票。…

css 包含块

你不知道的 CSS 之包含块 一说到 CSS 盒模型,这是很多小伙伴耳熟能详的知识,甚至有的小伙伴还能说出 border-box 和 content-box 这两种盒模型的区别。 但是一说到 CSS 包含块,有的小伙伴就懵圈了,什么是包含块?好像…

【啃】《Java核心卷 一》 | 第一,二章

文章目录 《Java核心技术卷 一》第一章 概述第二章 Java编程环境 图书推荐 《Java核心技术卷 一》 第一章 概述 前言:本书与一些”0基础入门“的书定位感觉是不太一样的,可能就像书名所说,是”核心技术“叭。书中经常将Java语言与 c 进行对比…

无损网络理论和实践

一、为什么需要无损网络? 随着高性能计算、大数据分析、人工智能以及物联网等技术的飞速发展,集中式存储、分布式存储以及云数据库的普及等原因,业务应用有越来越多的数据需要从网络中获取,这对数据中心网络的交换速度和性能要求…

Linux :: 权限篇:【1】:Linux 下文件访问者身份说明:三人一组!【补充:Linux下用户类型的分类!】

系列文章说明 前言:本篇是 Linux 基本操作篇章的内容! 笔者使用的环境是基于腾讯云服务器:CentOS 7.6 64bit。 学习集推荐: C 入门到入土!!!学习合集Linux 从命令到网络再到内核!学习…

【Flutter】Flutter 如何调用另一个 Page 里的函数

文章目录 一、前言二、状态管理和页面函数调用1. 状态管理简介2. 页面函数调用的需求 三、方法介绍和示例1. Provider 方法2. Global Key 方法3. 回调函数方法 四、总结 一、前言 本文的目标是为 Flutter 初学者解释如何在 Flutter 中调用另一个 Page 里的函数。通过阅读本文&…

碳排放预测模型 | Python实现基于机器学习回归分析的碳排放预测模型——数据清理和准备

文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 碳排放预测模型 | Python实现基于机器回归分析的碳排放预测模型——数据清理和准备 研究内容 分析国家在设计用于预测和预测二氧化碳排放的机器学习模型方面的特定记录,利用来自全球绝大多数国家的记录。…

探索iOS之Metal编程指南

iOS推出Metal渲染库为了取代OpenGL。Metal有自己的Shader语言,渲染效率比OpenGL高。在这里我们一起探索:Metal使用C限制、预处理定义、动态链接配置、GPU编译配置、设备坐标系、视口坐标系、纹理坐标系、矢量类型、矩阵类型、采样器状态、矩阵相乘。 1、…

如何下载远程maven仓库的jar 手动放到本地仓库?

文章目录 如何下载远程maven仓库的jar 手动放到本地仓库?简单步骤描述:详细步骤描述:案例1:案例2:结语如何下载远程maven仓库的jar 手动放到本地仓库? 在使用Maven构建Java项目时,通常会从中央仓库或其他远程仓库下载所需的依赖库。但是,有时候我们需要手动下载这些依赖库并…

Java并发之 Lock 锁

一、Lock接口 1 Lock简介&地位&作用 锁是一种工具,用于控制对共享资源的访问Lock和synchronized是最常见的两个锁,他们都能够达到线程安全的目录,但是使用和功能上又有较大的不同Lock接口最常见的实现类就是ReentrantLock通常情况下…

【LeetCode热题100】打卡第21天:最小路径和爬楼梯

文章目录 【LeetCode热题100】打卡第21天:最小路径和&爬楼梯⛅前言 最小路径和🔒题目 爬楼梯🔒题目🔑题解 【LeetCode热题100】打卡第21天:最小路径和&爬楼梯 ⛅前言 大家好,我是知识汲取者&#…

深入了解RTMP协议:实时传输的利器

😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD 如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。😊 座右铭:不想…

【环境配置】MATLAB r2022b+opencv3.4.1+mexopencv3.4.1+Windows 11 配置

参考链接: mexopencv官方文档:介绍了全部流程 补充官方文档Configure OpenCV出现的问题:直到Configure后没有红色,再点击Generate 最新Opencv 与 VC 的版本对应关系(2023-04-08) MATLAB支持和兼容的编译器 …

大学物理(上)-期末知识点结合习题复习(5)——刚体力学-转动惯量、力矩、线密度 面密度 体密度、平行轴定理和垂直轴定理、角动量定理和角动量守恒定律

目录 刚体的定轴转动 题1 题目描述 题解 题2 题解 题3 题目描述 题解 题4 题目描述 题解 题5 题目描述 题解 角动量定理和角动量守恒定律 刚体的定轴转动 1.转动动能 由,得 表示质量 表示质量分布点 2.转动惯量 为刚体对给定轴的转动惯量&…

原生小程序 微信小程序 使用ucharts

一般是uni-app项目使用ucharts在原生微信小程序也是可以使用。 方法: ## 使用说明 请将项目根目录 微信小程序/uCharts-组件/qiun-wx-ucharts/src 下全部文件复制到指定位置,例如该项目的components/qiun-wx-uchart目录下,然后在页面的json配…

2023互联网寒冬之下Java程序员要怎么应对才能找到工作

在互联网寒冬下,Java程序员需要做好哪些方面的准备,才能够更好地找到工作呢? 1.关注用人单位的招聘需求;Java程序员应该关注用人单位的招聘信息,并针对不同的招聘岗位进行精准的自我定位和筛选。在面试前可以充分了解…

Gin框架原生方式切割日志,Go语言原生日志切割

目录 摘要 痛点 正文 1.分析 io.Writer 接口 2.实现 io.Writer 接口 3.将它作为原生输出 4.将它作为 Gin 框架的输出 摘要 自定义一个日志输出,将go语言和gin框架的日志自动按天拆分。本文通过实现io.Writer接口的方式,替换原生和gin框架的默认W…

DAY21——二叉树part7

1.二叉搜索树最小差值 二叉搜索树中序遍历得到有序的数字序列,记录前一个节点 class Solution {TreeNode pre;int result Integer.MAX_VALUE;public int getMinimumDifference(TreeNode root) {if(rootnull)return 0;traversal(root);return result;}private voi…

【Java算法题】剑指offer_数据结构之03队列栈

前言 刷题链接: https://www.nowcoder.com/exam/oj/ta?page2&tpId13&type265 原定于5.30写完队列&栈,超时了14天(2周),于6.13完成。 刷算法题到现在得出一个心得,万事开头难。没刷之前总觉得…