1.2 C/C++ 内存

一、C++ 内存管理

程序的虚拟地址空间通常划分为:代码段、数据段、BSS 段、堆区、文件映射区、栈区

注意:段的划分由编译器决定,虚拟地址布局与物理内存分配由操作系统管理,这句话面试官是问过我的

文件映射区:主要用于加载动态链接库,以及实现外存文件到虚拟地址空间的映射

二、C 语言中,内存分配的方式有几种?

​ 1、静态存储区分配:内存分配在编译前完成,且在程序的整个运行期间存在。

​ 2、栈上分配:函数内的局部变量。

​ 3、堆上分配。

三、堆与栈的区别?

​ 1、申请方式上:栈自动分配,堆手动分配。

​ 2、申请大小限制:栈由高地址向低地址开辟,并且连续,但是空间小;堆由低地址向高地址开辟,不连续,但是大。

​ 3、申请效率:栈由系统自动分配,速度快;堆人为分配,速度慢。

​ 4、生命周期:堆需要手动释放,并且不受函数调用关系限制;栈自动释放。

​ 5、能否产生内存碎片:栈不会;堆可能会。

四、栈在 C 语言中有什么作用?

​ 1、可以用来存储临时变量,如,局部变量,函数参数,函数返回值,函数中的临时变量,寄存器值,函数返回地址等。

​ 2、栈是多线程编程的基石,每个线程都最少有一个专属的栈。

​ 3、中断和异常处理也有专属的栈。

五、C 语言函数参数的压栈顺序

​ C 语言采用自右向左的方式对函数参数压栈,这样处理起来比较方便,如 printf。

六、C++ 中拷贝赋值构造函数可以按值传递吗?

​ 不可以,如果按值传递,传入参数本身就是一个临时对象,那这样的话,需要先对函数参数对象进行拷贝复制构造函数,这样就会造成死循环。

七、内存泄露

​ 申请了一段堆空间,但在使用结束后并没有对其释放。虽然在程序结束后,系统可以对其释放,但在程序运行期间,这部分内存空间无法被其他进程申请。(所以这就引出了智能指针,关于智能指针的考点在后续章节)

八、内存溢出

定义:程序在运行过程中尝试访问超过其分配内存空间范围的内存区域。

常见情况:1、栈溢出(函数调用中递归层级过深,或者局部变量所需空间太大,超出栈的范围)。

​ 2、缓冲区溢出(当向一个固定大小的缓冲区写入超过其容量的数据时,会导致写到相邻内存区域,如strcpy)。

​ 3、数据溢出(如使用malloc分配的空间小,但写入的数据超过所分配的内存空间)。

九、strcpy 与 memcpy 的区别?

strcpy 用于字符串拷贝,直到遇到 '\0' 停止,仅适用于字符串。memcpy 用于字节级别的拷贝,会直接从源地址复制指定个字节到目标地址。

strcpy(dest, src);
memcpy(dest, src, n);

十、重写 memcpy 需要注意的问题

检查内存是否有重叠,如果有需要从后向前拷贝,避免覆盖。

入参检查:指针有效性、size 应为正数。

尽量按机器字长拷贝,减少内存访问次数。

十一、malloc、calloc区别?

malloc:只是分配内存块;calloc:不仅分配指定大小的内存块,还会将内存中的内容初始化为 0;

int* arr = (int*)calloc(5, sizeof(int)); // 分配并清零

int* arr = (int*)malloc(5 * sizeof(int));
memset(arr, 0, 5 * sizeof(int)); // 等效calloc的效果

十二、malloc 底层原理

​ 1、当开辟的空间小于 128K 时,调用 brk() 函数,malloc 的底层实现是系统调用函数 brk(),其主要移动指针 _enddata (此时的 _enddata 指的是 Linux 地址空间中堆段的末尾地址,不是数据段的末尾地址)。

​ 2、当开辟的空间大于 128K 时,mmap()系统调用函数来在虚拟地址空间中(堆和栈中间,称为“文件映射区域”的地方)找一块空间来开辟。

具体实现:

​ 1、当调用 malloc(size) 时,它首先计算需要分配的内存块大小,包括用户请求的大小以及内存管理所需的额外空间(例如内存块的管理信息)。

​ 2、malloc 会遍历一个数据结构(例如空闲链表或空闲块列表),查找合适大小的空闲内存块。

​ 3、如果找到了合适的内存块,malloc 会将其标记为已分配,并返回一个指向该内存块的指针给用户。

​ 4、如果没有足够大的空闲内存块可用,malloc 可能需要扩展程序的虚拟内存空间。它通过系统调用(例如 brk 或 mmap)向操作系统请求更多的连续内存空间。

​ 5、当操作系统提供了更多的内存空间后,malloc 可以从新的空间中分配出合适大小的内存块,并将其标记为已分配。

​ 6、在内存块被释放时,通过调用 free 函数,malloc 将其标记为未分配,并将该内存块添加到空闲内存块的列表中,以便后续的内存分配可以重复使用它们。

C++/嵌入式开发 秋招面经 文章被收录于专栏

一名985硕,在25年秋招中斩获多个C++/嵌入式开发Offer。本专栏将分享我的面经,涵盖C/C++、操作系统、计算机网络、ARM体系与架构、Linux应用/驱动开发、Qt、通信协议及开发工具链等核心内容。

全部评论

相关推荐

点赞 评论 收藏
分享
1. 自我介绍1.5 面试官特意提了一嘴一面面试官给我的面评,不知道何意味?2. 项目相关(有些记不清了,下面这些应该不全)2.1 总体介绍项目2.2 io_uring和epoll的对比,为什么选用io_uring,讲讲心路历程2.3 协程与线程的区别2.4 Raft共识算法与Paxos的对比2.5 Raft如何保持数据一致性2.6 Raft为什么在高并发情况下性能下降3. 设计题:(面试官让共享屏幕直接使用agent作答,估计是想看看我平时是怎么使用agent的)3.1 使用agent设计一个社交平台的用户好友关系、关注信息的系统3.2 假如一个几千万粉丝的大V发动态了,怎么让关注了他的用户接收到他的更新(涉及什么推拉结合)3.3 根据agent给出的系统架构(Redis+DB),如果Redis整个集群挂了,所有用户请求直接打到数据库中,会导致数据库崩溃,设计限流机制。4. 反问:4.1 部门用Go吗?(问这个问题是为了向面试官表示我正在主动积极学Go,刷个印象分)4.2 agent对行业的冲击,同事之间会讨论吗,你们对agent代替程序员的看法?4.3 目前实际生产中agent的参与程度4.4 后续流程(这里面试官直接说后面等HR面嘻嘻)无手撕,很惊喜,因为一面手撕没撕出来以为二面还会狠狠拷打算法注:最后的设计题我答得稀烂,业务层面的设计、Redis和数据库我都不怎么了解,虽然我在看Java面经的时候经常看到这些业务设计题,但没有意识去刻意了解。后来跟面试官坦白说因为学的C++,没怎么关注业务层面,面试官人很好,表示理解。感谢面试官(还有面试官长得像桑杰,我一看他就想笑),还是要补补后端业务层面的知识!冲冲冲!!!后续:二面面完两小时秒过,约HR面
查看13道真题和解析
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
正在热议
更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务