0%

C++ problems

指针和引用的区别

指针所指向的内存空间在程序运行过程中可以改变,而引用所绑定的对象一旦绑定就不能改变。(是否可变)
指针本身在内存中占有内存空间,引用相当于变量的别名,在内存中不占内存空间(是否占内存)
指针可以为空,但是引用必须绑定对象(是否可为空)
指针可以有多级,但是引用只能一级(是否能为多级)

堆和栈的区别

申请方式:栈是系统自动分配,堆是程序员主动申请
申请后系统响应:分配栈空间,如果剩余空间大于申请空间则分配成功,否则分配失败栈溢出;申请堆空间,堆在内存中呈现的方式类似于链表(记录空闲地址空间的链表),在链表上寻找第一个大于申请空间的节点分配给程序,将该节点从链表中删除,大多数系统中该块空间的首地址存放的是本次分配空间的大小,便于释放,将该块空间上的剩余空间再次连接在空闲链表上
栈在内存中是连续的一块空间(向低地址扩展)最大容量是系统预定好的,堆在内存中的空间(向高地址扩展)是不连续的
申请效率:栈是有系统自动分配,申请效率高,但程序员无法控制;堆是由程序员主动申请,效率低,使用起来方便但是容易产生碎片
存放的内容:栈中存放的是局部变量,函数的参数;堆中存放的内容由程序员控制

new 和 delete 是如何实现的,new 与 malloc 的异同处

在使用的时候 new,delete 搭配使用,malloc 和 free 搭配使用。

属性:malloc/free 是库函数,需要头文件的支持;new/delete 是关键字,需要编译器的支持
参数:new 申请空间时,无需指定分配空间的大小,编译器会根据类型自行计算;malloc 在申请空间时,需要确定所申请空间的大小
返回值:new 申请空间时,返回的类型是对象的指针类型,无需强制类型转换,符合类型安全的操作符;malloc 申请空间时,返回的是 void* 类型,需要进行强制类型的转换,转换为对象类型的指针
分配失败:new 分配失败时,会抛出 bad_alloc 异常,malloc 分配失败时返回空指针
重载:new/delete 支持重载,malloc/free 不能进行重载
自定义类型实现:new 首先调用 operator new 函数申请空间(底层通过 malloc 实现),然后调用构造函数进行初始化,最后返回自定义类型的指针;delete 首先调用析构函数,然后调用 operator delete 释放空间(底层通过 free 实现)。malloc/free 无法进行自定义类型的对象的构造和析构
内存区域:new 操作符从自由存储区上为对象动态分配内存,而 malloc 函数从堆上动态分配内存。(自由存储区不等于堆)

C 和 C++ 的区别

C 是面向过程的编程,特点是函数;C++ 是面向对象的编程,特点是类。(特性)
C 主要用在嵌入式开发、驱动开发和硬件直接打交道的领域;C++ 可以用于应用层的开发、用户界面开发等和操作系统直接打交道的领域。(应用领域)
C++ 继承了C的底层操作特性,增加了面向对象的机制,增加了泛型编程、异常处理、运算符重载,还增加了命名空间,避免了命名冲突。(相较于 C 的升级)

C++和java的区别

Struct 和 class 的区别

struct 和 class 都可以自定义数据类型,也支持继承操作

struct 中默认的访问级别是 public,默认的继承级别也是 public
class 中默认的访问级别是 private,默认的继承级别也是 private
当 class 继承 struct 或者 struct 继承 class 时,默认的继承级别取决于继承的是 class(public) 还是 struct(private)
class 可以定义模板参数,struct 也可以

define 和 const 的区别(编译阶段、安全性、内存占用等)

编译阶段:define 是在编译预处理阶段起作用,const 是在编译阶段和程序运行阶段起作用
安全性:define 定义的宏常量没有数据类型,只是进行简单的替换,不会进行类型安全的检查;const 定义的只读变量是有类型的,是要进行判断的,可以避免一些低级的错误
内存占用:define 定义的宏常量,在程序中使用多少次就会进行多少次替换,内存中有多个备份;const 定义的只读变量在程序运行过程中只有一份
调试:define 定义的不能调试,因为在预编译阶段就已经进行替换了;const 定义的可以进行调试
const 的优点:

有数据类型,在定义式可进行安全性检查
可调式
占用较少的空间

const static 用法和作用

STL 源码中的 hash 表的实现

hashtable 是采用开链法来完成的,(vector + list)

底层键值序列采用 vector 实现,vector 的大小取的是质数,且相邻质数的大小约为 2 倍关系,当创建 hashtable 时,会自动选取一个接近所创建大小的质数作为当前 hashtable 的大小;
对应键的值序列采用单向 list 实现;
当 hashtable 的键 vector 的大小重新分配的时候,原键的值 list 也会重新分配,因为 vector 重建了相当于键增加了,那么原来的值对应的键可能就不同于原来分配的键,这样就需要重新确定值的键。

STL 中 unordered_map 和 map 的区别

底层实现不同:
unordered_map 底层实现是一个哈希表,元素无序
map 底层实现是红黑树,其内部所有的元素都是有序的,因此对 map 的所有操作,其实都是对红黑树的操作
优缺点:
unordered_map:查找效率高;但是建立哈希表比较耗费时间
map:内部元素有序,查找和删除操作都是 logn 的时间复杂度;但是维护红黑树的存储结构需要占用一定的内存空间
适用情况:
对于要求内部元素有序的使用 map,对于要求查找效率的用 unordered_map

C++ 内存管理(热门问题,问过)

C++ 内存分区:栈、堆、自由存储区、全局/静态存储区、常量区

栈:存放函数的局部变量,由编译器自动分配和释放
堆:动态申请的内存空间,就是由 malloc 分配的内存块,由程序员控制它的分配和释放,如果程序执行结束还没有释放,操作系统会自动回收
自由存储区:和堆十分相似,存放由 new 分配的内存块,由 delete 释放内存
全局区/静态区:存放全局变量和静态变量
常量存储区:存放的是常量,不允许修改

堆和自由存储区的区别:

参考链接:🔗 这里

自由存储是 C++ 中通过 new 与 delete 动态分配和释放对象的抽象概念,而堆是 C 语言和操作系统的术语,是操作系统维护的一块动态分配内存
new 所申请的内存区域在 C++ 中成为自由存储区。藉由堆实现的自由存储,可以说 new 所申请的内存区域在堆上
堆和自由存储区有区别,并非等价。使用 new 来分配内存,程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。

内存泄漏

内存泄漏常指的是堆内存泄漏,当然还包括系统资源的泄漏

野指针

指针指向的内存空间已经释放掉

悬挂指针

指针指向的内存空间由于中间改变了其指向,之前的内存空间已无法释放,个人认为是和内存泄漏。