【C++基础】C++内存处理机制面试题(以面促学 )
🌈欢迎来到C++基础专栏
🙋🏾♀️作者介绍:前PLA队员 目前是一名普通本科大三的软件工程专业学生
🌏IP坐标:湖北武汉
🍉 目前技术栈:C/C++、Linux系统编程、计算机网络、数据结构、Mysql、Python(目前在学)
🍇 博客介绍:通过分享学习过程,加深知识点的掌握,也希望通过平台能认识更多同僚,如果觉得文章有帮助,请您动动发财手点点赞,本人水平有限,有不足之处欢迎大家扶正~
🍓 最后送大家一句话共勉:知不足而奋进,望远山而前行。
————————————————
C++内存
- 1. 简述一下堆和栈的区别
- 2.简述C++的内存管理
- 1. 内存分配方式:
- 2. 常见的内存错误及其对策:
- 3. 内存泄露及解决办法:
- 什么是内存泄露?
- 怎么检测?
- 4. malloc和局部变量分配在堆还是栈?
- 一个程序有哪些section:
- 初始化为0的全局变量在bss还是data
- 5.简述C++中内存对齐的使用场景
- 1. 什么是内存对齐?
1. 简述一下堆和栈的区别
参考回答
区别:
- 堆栈空间分配不同。栈由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等;堆一般
由程序员分配释放。 - 堆栈缓存方式不同。栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立
即释放;堆则是存放在二级缓存中,速度要慢些。 - 堆栈数据结构不同。堆类似数组结构;栈类似栈结构,先进后出。
2.简述C++的内存管理
参考回答
1. 内存分配方式:
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
堆,就是那些由new分配的内存块,一般一个new就要对应一个delete。
自由存储区,就是那些由malloc等分配的内存块,和堆是十分相似的,不过是用free来结束自己的生命。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中
常量存储区,这是一块比较特殊的存储区,里面存放的是常量,不允许修改。
2. 常见的内存错误及其对策:
(1)内存分配未成功,却使用了它。
(2)内存分配虽然成功,但是尚未初始化就引用它。
(3)内存分配成功并且已经初始化,但操作越过了内存的边界。
(4)忘记了释放内存,造成内存泄露。
(5)释放了内存却继续使用它。
对策:
(1)定义指针时,先初始化为NULL。
(2)用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
//const* 是常量指针,*const 是指针常量
int const *a; //a指针所指向的内存里的值不变,即(*a)不变
int *const a; //a指针所指向的内存地址不变,即a不变
(3)不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
(4)避免数字或指针的下标越界,特别要当心发生“多1”或者“少1”操作
(5)动态内存的申请与释放必须配对,防止内存泄漏
(6)用free或delete释放了内存之后,立即将指针设置为NULL,防止“野指针”
(7)使用智能指针。
3. 内存泄露及解决办法:
什么是内存泄露?
简单地说就是申请了一块内存空间,使用完毕后没有释放掉。
(1)new和malloc申请资源使用后,没有用delete和free释放;
(2)子类继承父类时,父类析构函数不是虚函数
(3)Windows句柄资源使用后没有释放。
怎么检测?
第一:良好的编码习惯,使用了内存分配的函数,一旦使用完毕,要记得使用其相应的函数释放掉。
第二:将分配的内存的指针以链表的形式自行管理,使用完毕之后从链表中删除,程序结束时可检查改链表。
第三:使用智能指针。
第四:一些常见的工具插件,如ccmalloc、Dmalloc、Leaky、Valgrind等等。
4. malloc和局部变量分配在堆还是栈?
参考回答
malloc是在堆上分配内存,需要程序员自己回收内存;局部变量是在栈中分配内存,超过作用域就
自动回收。
1.2.4 程序有哪些section,分别的作用?程序启动的过程?怎么判断数据分配在栈
上还是堆上?
一个程序有哪些section:
如上图,从低地址到高地址,一个程序由代码段、数据段、BSS段、堆、共享区、栈等组成。
- 数据段:存放程序中已初始化的全局变量和静态变量的一块内存区域。
- 代码段:存放程序执行代码的一块内存区域。只读,代码段的头部还会包含一些只读的常数变量。
- BSS 段:存放程序中未初始化的全局变量和静态变量的一块内存区域。
- 可执行程序在运行时又会多出两个区域:堆区和栈区。
堆区:动态申请内存用。堆从低地址向高地址增长。
栈区:存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。 - 最后还有一个共享区,位于堆和栈之间。
程序启动的过程: - 操作系统首先创建相应的进程并分配私有的进程空间,然后操作系统的加载器负责把可执行文件的数据段和代码段映射到进程的虚拟内存空间中。
- 加载器读入可执行程序的导入符号表,根据这些符号表可以查找出该可执行程序的所有依赖的动态
链接库。 - 加载器针对该程序的每一个动态链接库调用LoadLibrary
(1)查找对应的动态库文件,加载器为该动态链接库确定一个合适的基地址。
(2)加载器读取该动态链接库的导入符号表和导出符号表,比较应用程序要求的导入符号是否匹配该库的导出符号。
(3)针对该库的导入符号表,查找对应的依赖的动态链接库,如有跳转,则跳到3
(4)调用该动态链接库的初始化函数 - 初始化应用程序的全局变量,对于全局对象自动调用构造函数。
- 进入应用程序入口点函数开始执行。
怎么判断数据分配在栈上还是堆上:首先局部变量分配在栈上;而通过malloc和new申请的空间是在堆上
初始化为0的全局变量在bss还是data
参考回答
BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0。
5.简述C++中内存对齐的使用场景
参考回答
内存对齐应用于三种数据类型中:struct/class/union
struct/class/union内存对齐原则有四个:
- 数据成员对齐规则:结构(struct)或联合(union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小的整数倍开始。
- 结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储。(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的
整数倍开始存储)。 - 收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的"最宽基本类型成员"的整数倍。不足的要补齐。(基本类型不包括struct/class/uinon)。
- 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
*/
/*
相关文章:

【C++基础】C++内存处理机制面试题(以面促学 )
🌈欢迎来到C基础专栏 🙋🏾♀️作者介绍:前PLA队员 目前是一名普通本科大三的软件工程专业学生 🌏IP坐标:湖北武汉 🍉 目前技术栈:C/C、Linux系统编程、计算机网络、数据结构、Mysq…...

arcgis 批量删除字段
一、打开ArcToolbox-数据管理工具-字段-删除字段。 二、在输入表中选择要删除字段的要素,在删除字段栏中选择要删除的字段,点击确认即可。...

尚无忧球馆助教系统源码,助教小程序源码,助教源码,陪练系统源码
特色功能: 不同助教服务类型选择 助教申请,接单,陪练师入住,赚取外快 线下场馆入住 设置自己服务 城市代理 分销商入住 优惠券 技术栈:前端uniapp后端thinkphp 独立全开源...
Spring-集成Junit
一、引子 我们在Spring概念中提到:Spring的一大优势在于可以集成众多优秀的框架。毫无疑问,我首先向读者推荐的就是Junti框架。因为我们在前期的学习中,写一些小的demo,用Junit来进行小测试是非常合适的。下面让我们来具体看看如…...

DS:经典算法OJ题(1)
创作不易,友友们给个三连呗!! 本文为经典算法OJ题练习,大部分题型都有多种思路,每种思路的解法博主都试过了(去网站那里验证)是正确的,大家可以参考!! 一、移…...
最好理解文章——什么是闭包?
学习Javascript闭包(Closure) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用…...

Git 教程 | 将本地修改后的文件推送到 Github 指定远程分支上
Git 是一种分布式版本控制系统,用于敏捷高效地处理任何大小的项目。它是由 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的开源版本控制软件。Git 的本地克隆就是一个完整的版本控制存储库,无论脱机还是远程都能轻松工作。开发人员会在本地提交其工…...

漏洞原理linux操作系统的SqlMap工具的使用
漏洞原理linux操作系统的SqlMap工具的使用 Linux操作系统基础操作链接: 1024一篇通俗易懂的liunx命令操作总结(第十课)-CSDN博客 kali的IP地址:192.168.56.1 实操 # kali中使用sqlmap http://192.168.56.1/ sqlmap -u http://192.168.56.1/news/show.php?id46 sqlmap -u …...

【机器学习】欠拟合与过拟合
过拟合:模型在训练数据上表现良好对不可见数据的泛化能力差。 欠拟合:模型在训练数据和不可见数据上泛化能力都很差。 欠拟合常见解决办法: (1)增加新特征,可以考虑加入特征组合、高次特征,以…...

【C++】C++入门基础讲解(二)
💗个人主页💗 ⭐个人专栏——C学习⭐ 💫点击关注🤩一起学习C语言💯💫 导读 接着上一篇的内容继续学习,今天我们需要重点学习引用。 1. 引用 在C中,引用是一种特殊的变量ÿ…...

Requestly工具快速提升前端开发与测试的效率
痛点 前端测试 在进行前端页面开发或者测试的时候,我们会遇到这一类场景: 在开发阶段,前端想通过调用真实的接口返回响应在开发或者生产阶段需要验证前端页面的一些 异常场景 或者 临界值 时在测试阶段,想直接通过修改接口响应来…...
Node+Express写分页接口
后端逻辑 router.js文件 const express require(express); const router express.Router();//导入函数处理,数据 const articleMessage require(../router_handle/artcle)//文章列表 router.get(/list,articleMessage.articleList)module.exports router; router_handle.js…...

ifconfig 主机ip url记录
ifconfig 容器Pods相关主机与url信息 一文搞懂网络知识,IP、子网掩码、网关、DNS、端口号_关于ip,网关。端口-CSDN博客 计算机网络知识之URL、IP、子网掩码、端口号_ip地址和url-CSDN博客 阅读看下以上文章 由此可知 1.主机ip 10.129.22.124 10.129.22 是网段…...

RT-Thread: STM32 SPI使用流程
1.添加驱动 ①点开设置界面 ②勾选看门 SPI 驱动 ③点击保存 ④查看添加的驱动文件 drv_spi.c 2.打开驱动头文件定义 ①打开配置文件 ②打开定义 3.打开需要开启的SPI总线 打开 drivers 目录下的 board.h 用SPI搜索,找到如下文字,打开对应的宏。 /*-…...

Qt 基于海康相机 的视频标绘
需求: 基于 视频 进行 标注,从而进行测量。 曾经搞在线教育时,尝试在视频上进行文字或者图形的绘制,但是发现利用Qt widget 传sdk 句柄的方式,只能使用窗口叠加的方式(Qt 基于海康相机的视频绘图_海康相…...

【UEFI实战】Redfish的BIOS实现——生成EDK数据
生成Redfish文件 Redfish数据的表示形式,最常用的是JSON。将JSON表示的数据转换成C语言可以操作的结构体,是必不可少的步骤。当然如果手动转换的话,需要浪费大量的时间,因此DMTF组织开发了一个工具,用于将JSON数据快速…...

VUE--VUEX
一、什么是Vuex Vuex就是一个vue的状态(数据)管理工具,是vue项目实现大范围数据共享的技术方案。能够方便、高效的实现组件之间的数据共享。 Vuex的好处: (1)数据的存储一步到位,不需要层层传递…...

【NodeJS】004- NodeJS的模块化与包管理工具
模块化 1. 介绍 1.1.什么是模块化与模块 ? 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 模块化 其中拆分出的 每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用 1.2 什么是模块化项目 ? 编码时是按照模…...

Linux浅学笔记02
目录 grep-wc-管道符 echo-tail-重定向符 vi编辑器 grep-wc-管道符 grep命令(过滤文件内容) //更准确的来说,是筛选包括“所需字符”的一句内容或多句内容。 语法:grep [-n] 关键字 文件路径 //-n:可选,表示在结果中匹配的行…...
速盾:服务器CDN加速配置的技术文章
CDN(内容分发网络)是一种通过分布在不同地理位置的服务器来加速网站内容传输的技术。在本文中,我们将介绍如何使用服务器CDN加速配置,以提高网站的性能和用户体验。 一、什么是CDN加速? CDN加速是通过将网站的静态内…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...