热门话题白皮书HR资料
干货|近400道C++、嵌入式面试高频考点详解
2024.02.02


 阅读提示 

 本文内容全部摘自专刊《校招面试考点全解析——C++软件与嵌入式篇》



⭐⭐⭐⭐⭐考点汇总


1.结构体和共用体的区别


  • struct和union都是由多个不同的数据类型成员组成。struct的所有成员都存在;但在任何同一时刻, union中只存放了一个被选中的成员。

  • 在不考虑字节对齐的情况下,struct变量的总长度等于所有成员长度之和。Union变量的长度等于最长的成员的长度。

  • struct的不同成员赋值是互不影响的;而对于union的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了。


2.说说数组与指针


数组是相同类型数据的集合


引入数组就不需要在程序中定义大量的变量,大大减少了程序中变量的数量,使程序精炼,而且数组含义清楚,使用方便,明确地反映了数据间的联系。


许多好的算法都与数组有关,如洗牌算法、冒泡排序等。同时数组也是一种数据结构,它的特点就是可以常数时间复杂度O(1)地访问元素,但是插入与删除元素是O(n)的时间复杂度,所以当需要频繁插入删除元素时,尽量不用数组,或对数组进行一些改进优化,比如C++ vector容器就是在数组的基础上进行改进优化,提高了数组操作效率。


指针也是一种变量,但它和普通的变量的区别是,普通的变量存放的是实际的数据,而指针变量包含的是内存中的一块地址,这块地址指向某个变量或者函数。


指针是C/C++语言的核心的概念,大大提高了程序的灵活性,但是同时也隐藏着危机,如内存泄露、非法内存访问、野指针等。所以为了规避这些问题,在后来的C++11引入了智能指针帮助程序员。


3.请说说CPU的内核态与用户态


多数CPU都有两种模式,即内核态与用户态。通常,在PSW(Program Status Word,程序状态字寄存器)中有一个二进制位控制这两种模式。当在内核态运行时,CPU可以执行指令集中的每一条指令,并且使用硬件的每一种功能。相反的,用户程序在用户态下运行,仅允许执行整个指令集的一个子集和访问所有功能的一个子集。相对应的,内核态与用户态也是操作系统的两种运行级别。内核态拥有最高权限,可以访问所有系统指令;用户态则只能访问一部分指令。


在CPU的所有指令中,有一些指令是非常危险的,如果错用,将导致整个系统崩溃。比如:清内存、设置时钟等。所以区分内核态与用户态主要是出于安全的考虑。


4.请说说内存分布模型



从低地址到高地址,一个程序由代码段、数据段、 BSS 段组成。


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

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

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

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

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

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

  • 最后还有一个文件映射区,位于堆和栈之间。


5.如何避免野指针


  1. 初始化置NULL

  2. 申请内存后判空:malloc申请内存后需要判空,而在现行C++标准中,如C++11,使用new申请内存后不用判空,因为发生错误将抛出异常。

  3. 使用时不要超出指针作用域。

  4. 指针释放后置NULL

  5. 使用智能指针。


6.请你说说内存泄露


简单地说就是申请了一块内存空间,使用完毕后没有释放掉。


  1. new和malloc申请资源使用后,没有用delete和free释放;

  2. 子类继承父类时,父类析构函数不是虚函数。

  3. Windows句柄资源使用后没有释放。


有以下几种避免方法:


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

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

  3. 使用智能指针。

  4. 一些常见的工具插件可以帮助检测内存泄露,如ccmalloc、Dmalloc、Leaky、Valgrind等等。


7.堆内存申请需要注意什么?


  1. 不要错误地返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡。

  2. 不要返回了常量区的内存空间。因为常量字符串,存放在代码段的常量区,生命期内恒定不变,只读不可修改。

  3. 通过传入一级指针不能解决,因为函数内部的指针将指向新的内存地址。


解决办法:


  1. 使用二级指针

  2. 通过指针函数解决,返回新申请的内存空间的地址。


8.请你说说内存碎片


内存碎片通常分为内部碎片和外部碎片:


  1. 内部碎片是由于采用固定大小的内存分区,当一个进程不能完全使用分给它的固定内存区域时就产生了内部碎片,通常内部碎片难以完全避免;

  2. 外部碎片是由于某些未分配的连续内存区域太小,以至于不能满足任意进程的内存分配请求,从而不能被进程利用的内存区域。再比如堆内存的频繁申请释放,也容易产生外部碎片。


解决方法:


  1. 段页式管理

  2. 内存池


9.你怎么理解C语言和C++的区别?


  • C语言是C++的子集,C++可以很好兼容C语言。但是C++又有很多新特性,如引用、智能指针、auto变量等。

  • C++是面向对象的编程语言,C++引入了新的数据类型——类,由此引申出了三大特性:(1)封装。(2)继承。(3)多态。而C语言则是面向过程的编程语言。

  • C语言有一些不安全的语言特性,如指针使用的潜在危险、强制转换的不确定性、内存泄露等。而C++对此增加了不少新特性来改善安全性,如const常量、引用、cast转换、智能指针、try—catch等等;

  • C++可复用性高,C++引入了模板的概念,后面在此基础上,实现了方便开发的标准模板库STL(Standard Template Library)。STL的一个重要特点是数据结构和算法的分离,其体现了泛型化程序设计的思想。C++的STL库相对于C语言的函数库更灵活、更通用。


10.请说说CPU的内部架构和工作原理



CPU从逻辑上可以划分成3个部分,分别是控制单元、运算单元和存储单元,这三部分由CPU内部总线连接起来。


控制单元(CU, Control Unit):控制单元是整个CPU的指挥控制中心,由程序计数器PC (Program Counter)、 指令寄存器IR (Instruction Register)组成。程序计数器包含当前正在执行的指令的地址,在每个指令被获取之后,程序计数器指向顺序中的下一个指令。指令寄存器用于暂存当前正在执行的指令。


运算单元(ALU, Arithmetic Logic Unit):是运算器的核心。可以执行算术运算 (包括加减乘数等基本运算及其附加运算)和逻辑运算 (包括移位、逻辑测试或两个值比较)。


存储单元:包括CPU片内缓存和寄存器组,是CPU中暂时存放数据的地方,里面保存着那些等待处理的数据,或已经处理过的数据,CPU访问寄存器所用的时间要比访问内存的时间短。采用寄存器,可以减少CPU访问内存的次数,从而提高了CPU的工作速度。


CPU的运行原理就是:控制单元在时序脉冲的作用下,将程序计数器里所指向的指令地址送到地址总线上去,然后CPU将这个地址里的指令读到指令寄存器进行译码。对于执行指令过程中所需要用到的数据,会将数据地址也送到地址总线,然后CPU把数据读到CPU的内部存储单元(就是内部寄存器)暂存起来,最后命令运算单元对数据进行处理加工。这个过程不断重复,直到程序结束。



由于篇幅有限,本文目前先给大家分享以上这些题目啦~后面也会不断地来分享给大家的,当然如果有同学着急想看下面的内容也可以来订阅我们的专刊哦~


本专刊的作者蒋豆芽是湖南大学(985)硕士研究生(1%保研),校招面试过数十家公司,经验丰富,获得过华为、京东、顺丰科技等公司offer。目前为牛客网专刊作者。擅长机器学习、C++后台开发、嵌入式软件开发。


作者作为一个非科班研究生,立志进入互联网领域,最后通过自己的努力拿到大公司的offer,所以讲将自己的经历写入了专刊中,和大家分享春秋招的酸甜苦辣。同时也希望同学们可以通过学习专刊提升自己的求职竞争力,拿到一个满意的offer。


专刊一上线就得到了同学们的好评,作者也是针对同学们不同的基础情况给出了一些学习建议~



本专刊不仅给大家分享了大量的面试真题,还在真题讲解前给大家详细的讲解了知识点,以及面试必备的一些技能,而且作者的写作风格很有趣,让你在读故事的过程中就可以把知识点掌握了。可以给大家看一下我们内容的部分截图:


▲点击图片可查看大图▲


感兴趣的同学可以戳《校招面试考点全解析——C++软件与嵌入式篇》


直接购买,原价59元的专刊,现在仅需42元哦~


赶紧点击阅读原文,立即以优惠价格下单吧!



点击阅读原文立即优惠价购买

▼▼▼

▼▼▼