面试八股文(c++)

C++

1.多态,虚函数,纯虚函数的作用?

  • 多态:一个东西有多种形式。不同的对象,在收到相同的信息时产生不同的行为。
    好处:
    1.应用程序不必为每个派生类编写功能调用,只需要对抽象基类进行处理即可,大大提高程序的可复用性。
    2.派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。
  • 虚函数作用:允许派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
  • 纯虚函数作用:在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。

2.Struct和union的区别?

  • struct和union都是由多个不同的数据类型成员组成的,但是在任何同一时刻,union中只存放一个被选中的成员,而struct的所有成员都存在。
    在struct中,各成员都占有自己的内存空间,他们是同时存在的,一个struct变量的总长度等于所有成员长度之和,遵从字节对齐原则。在union中,所有成员不能同时占用它的内存空间,他们不能同时存在,union变量的长度等于最长的成员的长度。
  • 对于union的不同成员赋值,将会对其他成员重写,原来成员的值就不存在了,所以,共同体变量中起作用的成员是最后一次存放的成员;而struct的不同成员赋值是互不影响的。

3.Const和#define区别?

  • 编译器处理方式不同:#define宏是在预处理阶段展开的,不能对宏定义进行调试,而const常量是在编译阶段使用的
  • 类型和安全检查不同:#define宏没有类型,不做任何类型检查,仅仅是代码展开,可能产生边际效应等错误,而const常量有具体类型,在编译阶段会执行类型检查
  • 存储方式不同:#define宏仅仅是代码展开,在多个地方进行字符串替换,不会分配内存,存储于程序的代码段中,而const常量会分配内存,但只维持一份拷贝,存储在程序的数据段。
  • 定义域不同:#define宏不受定义域限制,而const常量只在定义域内有效。

4.内存泄漏的场景及解决方法有哪些?如何避免内存泄漏?

  • 常见场景:
    1.指针重新赋值在这里插入图片描述
    2.错误的内存释放
    在这里插入图片描述

3.返回值的不正确处理
在这里插入图片描述
4.在内存分配后忘记使用 free 进行释放
*

  • 解决方法:
    1.良好的编程习惯
    2.当在堆上申请了空间,一定记得释放
    3.使用c++的智能指针
    4.避免产生死锁情况
    5.打开的文件描述符一定记得关闭
    6.利用一些第三方工具,去检测内存泄漏。
  • 如何避免?
    1.确保没有访问空指针
    2.每次分配内存之后都应该有一个free函数与之对应,alloca函数除外。
    3.每次分配内存之后都应该及时进行初始化,可以结合memset函数进行初始化,calloc函数除外。
    4.每当向指针写入值时,都要确保可用字节数和所写入的字节数进行交叉核对
    5.对指针赋值前,一定要确保没有内存位置会变得孤立。
    6.每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应先遍历子内存位置并从那里开始释放,然后再遍历回父节点
    7.始终正确处理返回动态分配的内存引用的函数返回值。

5.TCP和UDP的区别?

这里是引用

6.TCP建立连接时三次握手,为啥断开时是四次挥手?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

7.常见的多线程之间线程同步的方式有哪些?实际用到的是哪个?

  • 互斥锁
  • 条件变量
  • 读写锁
  • 信号量
  • 几种线程同步的方式各有利弊,实际开发中需要根据场景选择不同的方式使用开发

8.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到 ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于 LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的 ACK报文。

9.引用和指针的区别

  • 从大小来说:引用是别名,系统不会给引用分配存储单源,指针会占一定的空间,大小为地址总线个bit位
  • 从指向来说:引用不可以指向空值,指针可以。引用不可以修改指向,指针可以
  • 从初始化来说:引用在声明时必须初始化,而指针不必。
  • 从操作来说:引用实际上操作的就是对象本身,指针是间接操作对象

10.虚函数和纯虚函数的共同点和区别

  • 共同点:都可以被子类重写
  • 区别:纯虚函数只能在纯虚类中定义,而且不能有函数体,不可以实例化对象
    虚函数可以有自己的函数体,可以在任何类中定义,仍可以实例化对象

11.关于linux进程分类

按照进程的功能和运行的程序分类,进程可划分为两大类:
(1) 系统进程:可以执行内存资源分配和进程切换等管理工作;而且,该进程的运行不受用户的干预,即使是root用户也不能干预系统进程的运行。
(2) 用户进程:通过执行用户程序、应用程序或内核之外的系统程序而产生的进程,此类进程可以在用户的控制下运行或关闭。
针对用户进程,又可以分为交互进程、批处理进程和守护进程三类。
(1) 交互进程:由一个shell终端启动的进程,在执行过程中,需要与用户进行交互操作,可以运行于前台,也可以运行在后台。
(2) 批处理进程:该进程是一个进程集合,负责按顺序启动其他的进程。
(3) 守护进程:守护进程是一直运行的一种进程,经常在linux系统启动时启动,在系统关闭时终止。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。例如httpd进程,一直处于运行状态,等待用户的访问。还有经常用的crond进程,这个进程类似与windows的计划任务,可以周期性的执行用户设定的某些任务。"

12.nullptr调用成员函数可以吗?为什么?

能;原因:因为在编译时对象就绑定了函数地址,和指针空不空没关系。

13.c++为什么要引入weak_ptr?

  • shared_ptr和weak_ptr都是带有引用计数的智能指针,它俩的主要区别就是:
    shared_ptr可以改变引用计数的值,但是weak_ptr只是资源的观察者不会对资源的引用计数进行加1的操作
  • 使用场景
  1. 解决shared_ptr的循环引用问题

14.机器语言和高级语言各有什么特点

机器语言:能够 被机器立即识别并加以执行,具有执行速度快,占用内存小等优点;但难学,难记,难以推广使用
高级语言:弥补了机器语言的不足,不依赖于具体机器,容易理解,较为方便。

15.简要陈述指针的优缺点

优点:
1.提高程序效率
2.在调用函数时当指针指向的变量的值改变时,这些值能够为主调函数使用,即可以从函数调用得到多个可以改变的值;
3.可以实现动态存储分配
缺点:
容易出错,且错误往往比较隐藏,使用不当会出现隐藏的,难以发现和排除的故障。

16.静态库与动态库

1.静态库代码装载的速度快,执行速度略比动态库快。
2.动态库更加节省内存,可执行文件体积比静态库小很多。
3.静态库是在编译时加载,动态库是在运行时加载。
4.生成的静态链接库,Windows下以.lib为后缀,Linux下以.a为后缀。生成的动态链接库,Windows下以.dll为后缀,Linux下以.so为后缀。

17.请说明总线接口UART,I2C,USB的异同点(串/并、速率,全/半双工,总线拓扑等。

UART:通用异步串行口,速率不快,可全双工,结构上一般由波特率产生器、UART发送器、UART接收器组成,硬件上两线,一收一发;
I2C:双向、两线、串行、多主控接口标准。速率不快,半双工,同步接口,具有总线仲裁机制,非常适合器件间近距离经常性数据通信,可实现设备组网;
SPI:高速同步串行口,高速,可全双工,收发独立,同步接口,可实现多个SPI设备互联,硬件3~4线;
USB 通用串行总线,高速,半双工,由主机、hub、设备组成。设备可以与下级hub相连构成星型结构。

18.简述同步与异步的区别,阻塞与非阻塞的区别?

同步与异步的区别:
同步:是所有的操作都做完,才返回给用户结果。即写完数据库之后,再响应用户,用户体验不好。
异步:不用等所有操作都做完,就响应用户请求。即先响应用户请求,然后慢慢去写数据库,用户体验较好。
阻塞与非阻塞的区别:
阻塞:调用者调用了某个函数,等待这个函数返回,期间什么也不做,不停的检查这个函数有没有返回,必须等这个函数返回后才能进行下一步动作。
非阻塞:非阻塞等待,每隔一段时间就去检查IO事件是否就绪。没有就绪就可以做其他事情。

19.简述socket中select,epoll的使用场景和区别,epoll水平触发与边缘触发的区别?

select,epoll的使用场景:都是IO多路复用的机制,应用于高并发的网络编程的场景。I/O多路复用就是通过一种机制,可以监视多个文件描述符,一旦某个文件描述符就绪(一般是读就绪或者写就绪),能够通知应用程序进行相应的读写操作。
select,epoll的区别:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大;而epoll保证了每个fd在整个过程中只会拷贝一次。
(2)每次调用select都需要在内核遍历传递进来的所有fd;而epoll只需要轮询一次fd集合,同时查看就绪链表中有没有就绪的fd就可以了。
(3)select支持的文件描述符数量太小了,默认是1024;而epoll没有这个限制,它所支持的fd上限是最大可以打开文件的数目,这个数字一般远大于2048。
epoll水平触发与边缘触发的区别
LT模式(水平触发)下,只要这个fd还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作;
而在ET(边缘触发)模式中,它只会提示一次,直到下次再有数据流入之前都不会再提示了,无论fd中是否还有数据可读。

20.常用的linux命令

cd:切换当前目录
ls查看当前文件与目录
grep:通常与管道命令一起使用,用于对一些命令的输出进行筛选加工
cp:复制文件或文件夹
mv:移动文件或文件夹
rm:删除文件或文件夹
ps:查看进程情况
kill:向进程发送信号
tar:对文件进行打包
cat:查看文件内容
top:查看操作系统的信息,如进程,cpu占用率,内存信息等
free:查看内存使用情况
pwd:显示当前目录

21.TCP粘包问题

  • 多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若发送方发送数据包的长度和接收方在缓存中读取的数据包长度不一致,就会发生粘包,发送端可能堆积了两次数据,每次100字节一共在发送缓存堆积了200字节的数据,而接收方在接收缓存中一次读取120字节的数据,这时候接收端读取的数据中就包括了下一个报文段的头部,造成了粘包。
  • 解决粘包的方法:
  1. 发送方关闭Nagle算法,使用TCP_NODELAY选项关闭Nagle功能
  2. 发送定长的数据包。每个数据包的长度一样,接收方可以很容易区分数据包的边界
  3. 数据包末尾加上\r\n标记,模仿FTP协议,但问题在于如果数据正文中也含有\r\n,则会误判为消息的边界
  4. 数据包头部加上数据包的长度。数据包头部定长4字节,可以存储数据包的整体长度
  5. 应用层自定义规则 加分回答 造成粘包的因素有很多,有可能是发送方造成的,也有可能是接收方造成的。比如接收方在接收缓存中读取数据不及时,在下一个数据包到达之前没有读取上一个,可能也会造成读取到超过一个数据包的情况。

22 简述 C++ 的内存管理

C++ 的内存分区主要有:代码区、未初始化数据区(BSS)、已初始化数据区(DATA)、栈区(Stack)、堆区(Heap)

  1. 代码区 加载的是可执行文件代码段,所有的可执行代码都加载到代码区,这块内存是不可以在运行期间修改的。
  2. 未初始化数据区 加载的是可执行文件 BSS 段,位置可以分开也可以紧靠数据段,存储于数据段的数据(全局未初始化,静态未初始化数据)的生存周期为整个程序运行过程。
  3. 已初始化数据区(全局初始化数据区/静态数据区) 加载的是可执行文件数据段,存储于数据段(全局初始化,静态初始化数据,文字常量(只读))的数据的生存周期为整个程序运行过程。
  4. 栈区 栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的生存周期为申请到释放该段栈空间。
  5. 堆区 堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序,用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。
  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南方的守候

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值