当前位置: 首页 > news >正文

【c++面试总结】

1. NULL 和 nullptr 区别

int overLoadTest(int x) {cout << __LINE__ << endl;return 0;
}int overLoadTest(char* x) {cout << __LINE__ << endl;return 0;
}int main() {char x[10] = {1,2,3,4,5};overLoadTest(1);overLoadTest(x);overLoadTest(nullptr);// overLoadTest(NULL); // ambiguousreturn 0;
}

在这里插入图片描述

  • 结论:
    1. NULL 的定义 实际是 0;在重载函数中传入 NULL 具有二义性,编译器无法对 0 和 空指针类型区分
    1. nullptr 是c++11引入的安全的空指针字面量,不会被隐式转换为其他非指针类型,将去除二义性,可以安全的赋值给指针类型。

2. static 作用

  1. static 修饰变量或函数改变该变量的作用域和生命周期。使其仅在该文件中可见,有效隐藏了static变量,可以避免命名冲突、降低代码耦合度。
    static函数存储在代码段
    static变量存储在全局数据段
  2. 底层实现
    符号本地化:
    ` 编译:编译器生成的符号具有内部链接属性,只在当前编译单元可见
    · 链接:链接器不会将static符号输出到其他模块,也不会将其他模块同名函数输入。
    符号解析:
    · 链接器在链接阶段会解析符号引用,对于static符号,只会查找当前模块内的定义,不会从其他模块寻找。
    · 如果其他文件尝试引用static类型符号,链接器会报为解析符号引用,因为该符号不会出现在其他模块符号表中。

3. free()函数只传入一个地址,为什么知道释放空间大小

malloc分配的内存为一个个chunk,定义如下:

struct malloc_chunk {    size_t prev_size;  /* 前一个内存块的大小(如果合并的话) */    size_t size;       /* 当前内存块的大小,包括边界标记 */    struct malloc_chunk *fd;  /* 指向前一个空闲内存块的指针(用于空闲内存列表) */    struct malloc_chunk *bk;  /* 指向下一个空闲内存块的指针(用于空闲内存列表) */};

在这里插入图片描述
图片来自wx公众号“CppPlayer”
malloc分配内存后返回的指针不是指向Header,而是指向Payload的起始位置,所占用的空间大小记录在参数指针指向地址的前面,所以知道需要释放内存的大小

几个小知识:
malloc不是系统调用,通过 brk()从堆区分配内存 或 mmap()在文件映射区域分配虚拟内存。
只有当程序首次访问这片地址,操作系统通过MMU将虚拟地址转为物理地址,更新页表完成映射;如果这片内存实际没有使用过,不会分配实际的物理空间,节约内存。
调用free,内存不会马上被操作系统回收。为了减少与操作系统内存交互次数,降低系统开销。
首先会被内存管理器使用双链表等方式保存起来,有助于减少内存碎片和提高内存使用效率。

4. main()函数执行前还会执行什么代码

  1. 初始化全局变量
  2. 执行 全局对象 的构造函数
  3. 类内部声明的 静态成员对象 属于整个类而不是类的实例,因此提前初始化
  4. c运行时库初始化通常包括 设置缓冲区和初始化堆。c++可能进行初始化操作:设置运行环境、配置标准输入输出…

5. 堆和栈的数据访问速度

栈通常比堆块。
栈的数据存储在连续的内存单元,访问速度快;堆的数据存储在分散的存储空间,需要额外的指针解引用操作

栈特点:
自动管理:内存分配和回收由编译器自动处理
连续内存:栈内存一般连续,有助于优化cpu缓存
快速分配和回收:栈管理简单,分配和回收速度快
固定大小:栈大小通常在程序运行前就已经决定,超出后会发生栈溢出。
寻址方式:直接寻址

堆特点:
动态分配:显示分配
非连续内存:堆分配内存一般不连续,因为堆可以被分成多个部分,每部分可以独立回收和分配(内存碎片产生原因)
寻址方式:间接寻址

6. 构造函数不能为虚函数

  1. 从代码层面看
    虚函数表中存储了一个类所有虚函数的地址,它允许通过基类的指针调用派生类函数,实现运行时多态。
    虚表存储在只读数据段,虚函数表地址在编译时被确定,并链接到程序的二进制文件。
    当一个类被创建时,才会有虚表指针指向虚函数表,对象在没有初始化完成的时候不知道虚表位置,自然不能访问虚表内容
  2. 从设计角度看
    虚表的存在主要是为了解决 编译期间没办法确定具体调用对象的问题,但c++在编译期间就能确定要创建的对象具体类型,没有意义

http://www.mrgr.cn/news/40093.html

相关文章:

  • 基于SpringBoot+Vue的服装销售管理系统
  • ESXI识别USB设备
  • rdp远程桌面服务协议概述
  • 通信工程学习:什么是CSMA/CA载波监听多路访问/冲突避免
  • 【C#生态园】探秘自动化世界:六款顶尖自动化工具全面解析
  • 全同态加密算法概览
  • Vue Mini基于 Vue 3 的小程序框架
  • 中信银行西安分行:构建科技金融体质 做好科技金融“大文章”
  • 位运算(3)_判定字符是否唯一_面试题
  • 【重学 MySQL】四十三、多行子查询
  • 828华为云征文|华为云Flexus云服务器X实例部署——盲盒抽奖商城系统以及编译发布小程序
  • NAND Flash虚拟层初始化
  • 0-1开发自己的obsidian plugin DAY 6
  • linux驱动编程——等待队列
  • 如何利用 StarRocks 加速 Iceberg 数据湖的查询效率
  • 【C++篇】启航——初识C++(下篇)
  • MongoDB的查询/超详细/表达式符号
  • 脸爱云管理系统存在任意文件上传漏洞
  • 【C++算法】8.双指针_三数之和
  • Ubuntu VSCode Docker 权限