【秋招】嵌入式面试八股文-C语言 内存/预处理/其他

1 内存

1.1 C语言中内存分配的方式有几种?

(1)静态存储区分配

  • 内存分配在程序编译之前完成,且在程序的整个运行期间都存在,例如全局变量、静态变量等

(2)栈上分配

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

(3)堆上分配  

  • New开辟的空间在堆上

1.2 堆与栈有什么区别?

(1)申请方式

  • 栈的空间由操作系统自动分配/释放,堆上的空间手动分配/释放

(2)申请大小的限制栈空间有限

  • 在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是 一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow因此,能从栈获得的空间较小堆是很大的自由存储区堆是向高地址扩展的数据结构,是不连续的内存区域这是由于系统是用 链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址堆的大小受限于计算机系统中有效的虚拟内存由此可见,堆获得的空间比较灵活,也比较大

(3)申请效率

  • 栈由系统自动分配,速度较快但程序员是无法控制的
  • 堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便

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

  • C语言中栈用来存储临时变量,临时变量包括函数参数和函数内部定义的临时变量函数调用中和函数调用相关的函数返回地址,函数中的临时变量,寄存器等均保存在栈中,函数调动返回后从栈中恢复寄存器和临时变量等函数运行场景
  • 多线程编程的基础是栈,栈是多线程编程的基石,每一个线程都最少有一个自己专属的栈,用来存储本线程运行时各个函数的临时变量和维系函数调用和函数返回时的函数调用关系和函数运行场景。操作系统最基本的功能是支持多线程编程,支持中断和异常处理,每个线程都有专属的栈,中断和异常处理也具有专属的栈,栈是操作系统多线程管理的基石

1.4 C语言函数参数压栈顺序是怎样的?

  • 先理解入栈和出栈:

  • 栈的范围是由 ss * 10H  至 ss * 10H + sp
  • (ss)指堆栈寄存器:存放堆栈段起始地址的高16位(即16进制下五个数的前四个数)
  • (sp)指堆栈指针:用于存放栈顶的逻辑偏移地址
  • 栈的栈底指针不变,栈顶的指针随sp的改变而改变由于栈的栈底地址是高地址,栈顶地址是低地址所以当栈存入数据时,会先将sp减去存入数据的字节数,然后再将数据存入反之,当栈取出数据时,会将数据取出后将sp加上取出数据的字节数(例如,当sp=0800H,ss=2360H时,若此时加入20个字节的数据,那么就要将sp-20,此时的栈顶就是ss * 10H + sp)
  • 注:所谓高地址与低地址,前面的地址称为低地址,后面的地址称为高地址,例如23600H与23E00H,此时23600H为低地址,23E00H为高地址
  • 回答这个问题:从右至左
  • C语言参数入栈顺序的好处就是可以动态变化参数个数自左向右的入栈方式,最前面的参数被压在栈底除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反因此,C语言函数参数采用自右向左的入栈顺序,主要原因是为了支持可变长参数形式

例如:printf(const char* format,…)

  • printf函数是一个不定参函数
  • 编译器通过format的%占位符的个数来获取参数的个数
  • 假设函数压栈顺序是从左至右,format先入栈,各个参数再入栈,最后pc入栈入栈完之后,想知道参数的个数就要读取format,但要读取format就得知道参数的个数,陷入了一个死循环
  • 但是,如果函数压栈顺序是从右至左,未知个数的参数先入栈,format再入栈,最后压pc入栈这时候要想知道参数的个数只需要将栈顶指针加2即可读取到format

1.5 C++的内存管理是怎样的?

在C++中,虚拟内存分为代码段、数据段、BSS段、堆区、文件映射区以及栈区六部分

  • 代码段:包括只读存储区和文本区,其中只读存储区存储字符串常量,文本区存储程序的机器代码
  • 数据段:存储程序中已初始化的全局变量和静态变量
  • BSS段:存储未初始化的全局变量和静态变量(局部+全局),以及所有被初始化为0的全局变量和静态变量
  • 堆区:调用new/malloc函数时在堆区动态分配内存,同时需要调用delete/free来手动释放申请的内存
  • 映射区:存储动态链接库以及调用mmap函数进行的文件映射
  • 栈:使用栈空间存储函数的返回地址、参数、局部变量、返回值

1.6 什么是内存泄漏?

  • 简单地说就是申请了一块内存空间,使用完毕后没有释放掉
  • 它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了

1.7 如何判断内存泄漏?

  • 良好的编码习惯,尽量在涉及内存的程序段,检测出内存泄露当程式稳定之后,在来检测内存泄露时,无疑增加了排除的困难和复杂度使用了内存分配的函数,一旦使用完毕,要记得要使用其相应的函数释放掉
  • 将分配的内存的指针以链表的形式自行管理,使用完毕之后从链表中删除,程序结束时可检查改链表
  • Boost 中的smart pointer
  • 一些常见的工具插件,如ccmalloc、Dmalloc、Leaky等等

1.8 new/delete与malloc/free的区别是什么?

  • 在C++中,申请动态内存和释放动态内存,用new/delete 和 malloc/free都可以,new和malloc动态申请的内存都位于堆中,无法被操作系统回收,需要对应的delete/free来释放空间

void *malloc(int size);

  • 说明:malloc向系统申请分配指定size个字节的内存空间返回类型是 void* 类型void* 表示未确定类型的指针C,C++规定,void* 类型可以强制转换为任何其它类型的指针
  • 对于类的对象而言,malloc/free无法满足动态对象的

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

双非本,211硕。本硕均为机械工程,自学嵌入式,在校招过程中拿到小米、格力、美的、比亚迪、海信、海康、大华、江波龙等offer。八股文本质是需要大家理解,因此里面的内容一定要详细、深刻!这个专栏是我个人的学习笔记总结,是对很多面试问题进行的知识点分析,专栏保证高质量,让大家可以高效率理解与吸收里面的知识点!掌握这里面的知识,面试绝对无障碍!

全部评论

相关推荐

评论
1
12
分享

创作者周榜

更多
牛客网
牛客企业服务