C++ 复习笔记(面试问题)一

问:  C++与C 语言的区别

  •  c++ 支持带默认值的参数   参数可以从右到左给 , 可以在声明的时候给,也可以在定义的时候给  在函数调用的时候传入的参数为立即数  和有默认参数的不传参调用效率相同  ,而传入变量增加 mov 指令  如sum(10,10)  和sum(a+b);
  • c++ 支持函数重载 ,c语言编译器产生函数符号时:根据函数名生成  而c++会根据函数名和参数列表一起生成 ,所以函数名相同,参数列表不同(参数个数,参数类型),可以构成函数重载。(重载函数在编译阶段确定,call 指令需要函数的逻辑地址)
  • 动态申请空间的区别(malloc/free  new/delete)
  1. malloc 是c的库函数  new是运算符
  2. malloc  是按字节开辟空间,返回值需要类型强转,而new是按类型开辟  
  3. malloc 只负责申请内存,不初始化,new可以申请和初始化一起进行
  4. malloc 申请内存失败返回nullptr 而  new失败抛出异常
  5. 底层new是通过malloc  开辟的  但是优化于malloc
  6. delete也是运算符,而free是c库函数
  7. delete释放内存是先调用析构函数,在释放  ,而 free直接释放
  • c++的引用
  1.   引用&在底层是个常量指针(const *p)因此底层和指针一样,所占空间和指针相同
  2. 在功能方面可以满足指针的多数需求
  3. 比指针更为安全 指针可以为nullptr 而引用不能为空,必须要初始化对象,可以避免也指针,引用不进行地址操作,使得访问地址更安全
  4. 有const 指针没有const 引用
  5. 指针可以有多级指针,而饮用只有一级
  6. ++运算符意义不一样 指针是跳到连续地址的下一个对象  引用是对对象的操作
  7. 指针有自己的一块空间,引用没有
  8. 动态开辟空间返回要用指针,引用会引起内存泄露
  • struct 和class  struct默认类型为public 而class 为private 

问:c++ 和c 是本地编译语言,请问编译连接原理是什么?

      答:源文件经过  预编译-----形成(.i)文件-----编译(.s)文件------汇编(linux:.o)文件/(window:.obj) 文件-----链接(可执行文件)

  1.           预编译过程: 处理以#号开头的命令   展开头文件   进行宏替换  删除注释(注意#pragma lib  链接库在链接阶段  #pragma link 指定入口函数在链接阶段)
  2.           编译阶段:    语法语义编译,词法解释 代码优化
  3.           汇编阶段:    由汇编指令生成二进制指令  符号表的输出
  4.           链接阶段:    a:  所有.o文件字段合并,符号表合并,进行符号解析   b: 链接的核心:符号的从、重定位(a 完成后 符号分配了虚拟地址空间)

问: 全局变量和未初始化的全局变量有什么区别?

      答:程序运行的时候,数据需要从磁盘加载到物理内存中,Linux会为每个进程分配4G的虚拟地址空间,全局变量初始化过的会放在.data段,而未初始化的或者初始化为0的放在.bss段,.bss段不占用实际磁盘空间,程序执行前,全部清零。

问: 堆和栈的区别?

      答:(从地址空间分配开始回答):在x86体系下32位Linux系统中对于一个进程会有.text段,.rodata段, .data段, .bss段,.heap堆区 .stack栈区 ,栈区是系统分配的,由系统管理,以函数为单位,函数栈帧,局部变量,形参变量都放在栈的内存上,堆内存是程序员动态开辟 c语言用malloc/free  c++用new/delete 需要自己管理,因此很容易造成内存泄露,而栈不会,栈的内存分配效率高,内存是连续的,一般为2M或者10M (Linux上用ulimit -s查看 可修改),堆内存分配相对应栈要效率低一点,容易产生碎片,不一定连续。栈是由高地址向低地址开辟,堆是由低地址到高地址

拓展:

①管理方式:栈由编译器自动管理;堆由程序员控制,使用方便,但易产生内存泄露。

②生长方向:栈向低地址扩展(即”向下生长”),是连续的内存区域;堆向高地址扩展(即”向上生长”),是不连续的内存区域。这是由于系统用链表来存储空闲内存地址,自然不连续,而链表从低地址向高地址遍历。

③空间大小:栈顶地址和栈的最大容量由系统预先规定(通常默认2M或10M);堆的大小则受限于计算机系统中有效的虚拟内存,32位Linux系统中堆内存可达2.9G空间。

④存储内容:栈在函数调用时,首先压入主调函数中下条指令(函数调用语句的下条可执行语句)的地址,然后是函数实参,然后是被调函数的局部变量。本次调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的指令地址,程序由该点继续运行下条可执行语句。堆通常在头部用一个字节存放其大小,堆用于存储生存期与函数调用无关的数据,具体内容由程序员安排。

⑤分配方式:栈可静态分配或动态分配。静态分配由编译器完成,如局部变量的分配。动态分配由alloca函数在栈上申请空间,用完后自动释放。堆只能动态分配且手工释放。

⑥分配效率:栈由计算机底层提供支持:分配专门的寄存器存放栈地址,压栈出栈由专门的指令执行,因此效率较高。堆由函数库提供,机制复杂,效率比栈低得多。Windows系统中VirtualAlloc可直接在进程地址空间中分配一块内存,快速且灵活。

⑦分配后系统响应:只要栈剩余空间大于所申请空间,系统将为程序提供内存,否则报告异常提示栈溢出。

     操作系统为堆维护一个记录空闲内存地址的链表。当系统收到程序的内存分配申请时,会遍历该链表寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点空间分配给程序。若无足够大小的空间(可能由于内存碎片太多),有可能调用系统功能去增加程序数据段的内存空间,以便有机会分到足够大小的内存,然后进行返回。,大多数系统会在该内存空间首地址处记录本次分配的内存大小,供后续的释放函数(如free/delete)正确释放本内存空间。

     此外,由于找到的堆结点大小不一定正好等于申请的大小,系统会自动将多余的部分重新放入空闲链表中。

⑧碎片问题:栈不会存在碎片问题,因为栈是先进后出的队列,内存块弹出栈之前,在其上面的后进的栈内容已弹出。而频繁申请释放操作会造成堆内存空间的不连续,从而造成大量碎片,使程序效率降低。

     可见,堆容易造成内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和内核态切换,内存申请的代价更为昂贵。所以栈在程序中应用最广泛,函数调用也利用栈来完成,调用过程中的参数、返回地址、栈基指针和局部变量等都采用栈的方式存放。所以,建议尽量使用栈,仅在分配大量或大块内存空间时使用堆。

     使用栈和堆时应避免越界发生,否则可能程序崩溃或破坏程序堆、栈结构,产生意想不到的后果

问:c++中宏和内联函数的区别?

     答:  

  1. 宏替换发生在预编译阶段,是纯粹的字符串替换,而内联函数发生在编译阶段,有完整的语句检查,比宏安全
  2. 宏替换不会出现压栈出栈的开销,提高了效率,而inline函数本质上就是函数,在代码上比较简短,不能包含复杂的控制语句 switch,while....不能自身调用自身,否则会被编译器变成普通函数,因为内联函数在调用点直接展开,不会有函数调用开销,
  3. 内联函数不生成相应的函数符号

问:内联函数和普通函数的区别

    答  

  1. 内联函数和普通函数传参机制相同,但是编译器会在内联函数的调用点展开内联函数,因此没有函数调用的开销
  2. 普通函数调用,是在函数入口去执行函数体,函数本身只有一份,执行完会继续执行函数入口的下一行,而内联函数有N次调用,展开N次
  3. 内联函数有一定的限制,不能有复杂的控制语句,如果有,编译器也会将内联函数变成普通函数
posted @ 2020-02-23 17:08  睡觉lc  阅读(205)  评论(0编辑  收藏  举报