可以说个人秋招就要结束了,就等两个offer通知,然后签完搞定,这里提供一下自己复习的东西吧,我也就把这个东西给搞了一遍,然后面试基本没啥问题了,如果问的很深的话,那就只能只求多福了兄弟!其中可能有一些错误或者由于编译环境有差异请大家自动忽略这些错误【由于个人是搞ACM的,所以关于算法方面的东西就没有怎么提供了,不过大家把数据结构刷一遍是必要的】
信号的生命周期?
信号产生-》信号在进程中注册-》信号在进程中的注销-》执行信号处理函数
信号的产生方式?
(1)当用户按某些终端键时产生信号(2)硬件异常产生信号【内存非法访问】(3)软件异常产生信号【某一个条件达到时】(4)调用kill函数产生信号【接受和发送的所有者必须相同,或者发送的进程所有者必须为超级用户】(5)运行kill命令产生信号
信号处理方式?
(1)执行默认处理方式(2)忽略处理(3)执行用户自定义的函数
如何消除隐式转换?
使用explicit关键字进行修饰
重载,重写和隐藏的区别?
重载:即函数重载
重写【覆盖】:即用于虚函数
隐藏:只要派生类的函数名与基类相同就会隐藏
volatile表示什么?有什么作用?
易变的,不会被编译器进行优化,让程序取数据直接去内存中的。
Static_cast<>,dynamic_cast<>,const_cast<>,reinterpret_cast<>的各自作用和使用环境?
Static_cast:能完成大部分转换功能,但是并不确保安全
Const_cast:无法从根本上转变类型,如果是const,它就依旧是const,只是如果原对象不是const,可以通过此转换来处理,针对指针和引用而言。
Dynamic_cast:针对基类和派生类指针和引用转换,基类和派生类之间必须要继承关系,是安全的
Reinterpret_cast:允许将任何指针类型转为其他指针类型,是安全的
Malloc和new的区别?
New:
内存分配错误时,抛出bad_alloc异常,可以定义set_new_handler函数来在产生异常时进行处理;本身是一个运算符;分配内存的地方为自由存储区【为一个抽象概念】;对于对象而言,会先申请内存空间然后调用构造函数;无需指定大小
Malloc:
内存分配错误时,返回NULL;本身是一个库函数;分配内存的地方为堆;只申请内存空间;需要指定申请多大的内存;
free和delete的区别?
Delete:
本身是一个运算符
Free:
本身是一个库函数
free一个数组时如何知道要释放多大的内存呢?
一般在数组前面几个字节中存在某一个结构体来保存当前申请的数组大小。
__stdcall和__cdecl的区别?
__stdcall:
从右往左压栈,堆栈参数数据由函数本身清除,一般是通过汇编指令ret x,x表示弹出x个字节,参数必须是确定,必须为函数本身知晓,所以此关键字不能用于有可变参数应用的函数声明。
__cdecl:
从右往左压栈,由调用者来对堆栈数据进行清除,步骤:调用方调用函数-》函数执行-》函数结果返回-》调用方清除堆栈参数,主要针对可变参数
linux内部提供了那些调试宏?
__FILE__:表示在哪个文件
__LINE__:表示在当前多少行
__FUNCTION__:表示在执行在哪个函数
手写线程安全的单例模式?
引用和指针的区别?
指针:是一个变量类型;指针可以不进行初始化;指针初始化后可以改变,在写代码时需要大量的检测
引用:是一个别名;引用必须要初始化;引用初始化后不可改变,无需检测
出现异常时,try和catch做了什么?
Catch(Ep a)发生异常-》建立一个异常对象-》拷贝一个异常对象-》catch处理
Catch(Ep &a)发生异常-》建立一个异常对象-》引用异常对象-》catch处理
异常对象通常建立在全局或者堆中【需要在函数外进行捕捉】
Catch捕捉异常的转换:异常处理时,如果用基类的处理派生类的对象会导致派生类完全当做基类来使用,即便有虚函数也没用,所以派生类必须放在基类前处理。
C++如何处理多个异常的?
多次catch处理
常对象的成员变量一定不可以修改吗?为什么?
可以修改,用mutable来修饰,可以突破const的限制。
虚函数的调用过程?
找到对象内存中vfptr所指向虚函数表的地址-》找到虚函数表相应的虚函数地址
汇编层面:
Mov ecx, dword ptr[ebp-0ch]将this指针放进ecx
Mov edx, dword ptr[ecx]将虚表的地址放进edx
Call dword ptr[edx+4]:调用虚表中函数
虚函数放置顺序与声明顺序一样,成员变量也是
虚表中放的不是函数的入口地址,而是一个jmp跳转指令的地址
单继承,多继承,菱形继承,虚继承时,对象内存中的差异区别?如果存在虚函数呢?
单继承:
多继承:
菱形继承:
实现一个vector?是1.5还是2倍,各有什么优缺点?
1.5倍优势:可以重用之前分配但是释放的内存
2倍劣势:每次申请的内存都不可以重用
map底层用了什么?
红黑树
如果用map删除了一个元素,迭代器还能用吗?为什么?怎样做可以接着用?
能用,a.erase(it ++);因为是直接申请的内存,所以可以直接通过获取后续节点来处理
红黑树的特征是什么?
(1)根节点为黑色(2)一个节点为红色,子节点必定为黑色(3)从任意一点触发到达每一个叶子节点的黑色节点个数相同(4)每一个节点不是红色就是黑色(5)每一个叶子节点都是黑色
红黑树如何插入和删除的?
插入:
(1)如果父节点为黑色,直接插入不处理
(2)如果父节点为红色,叔叔节点为红色,则父节点和叔叔节点变为黑色,祖先节点变为红色,将节点操作转换为祖先节点
(3)如果当前节点为父亲节点的右节点,则以父亲结点为中心左旋操作
(4)如果当前节点为父亲节点的左节点,则父亲节点变为黑色,祖先节点变为红色,以祖先节点为中心右旋操作
删除:
(1)先按照排序二叉树的方法,删除当前节点,如果需要转移即转移到下一个节点
(2)当前节点,必定为这样的情况:没有左子树。
(3)删除为红色节点,不需要处理,直接按照删除二叉树节点一样
(4)如果兄弟节点为黑色,兄弟节点的两个子节点为黑色,则将兄弟节点变为红色,将着色转移到父亲节点
(5)如果兄弟节点为红色,将兄弟节点设为黑色,父亲结点设为红色节点,对父亲结点进行左旋操作
(6)如果兄弟节点为黑色,左孩子为红色,右孩子为黑色,对兄弟节点进行右旋操作
(7)如果兄弟节点为黑色,右孩子为红色,则将父亲节点的颜色赋值给兄弟节点,将父亲节点设置为黑色,将兄弟节点的右孩子设为黑色,对父亲节点进行左旋
红黑树和B+,B-的区别?
红黑树的深度比较大,而B+和B-的深度则相对要小一些,而B+较B-则将数据都保存在叶子节点,同时通过链表的形式将他们连接在一起。
线程同步几种方式?
互斥锁,信号量,临界区
手写strcpy,memcpy,memmove函数?
需要注意内存重叠问题
Do{}while(0)的用法有哪些?
(1)可以将语句当做一个独立的域(2)对于多语句可以正常的运行(3)可以有效的消除goto语句,达到跳转语句的效果
手写快排?时间复杂度?空间复杂度?能进行优化吗?还有吗?能进行尾递归优化吗?
最优时间复杂度:nlogn
最差时间复杂度:n^2
平均时间复杂度:nlogn
空间复杂度:logn -> n
优化:
(1)随机(2)三数取中(3)当排序达到一定长度时用插入排序(4)分隔一次后,将相同数据不处理(5)使用并行或者多线程(6)进行尾递归优化【即将logn降解为更低的复杂度】
线程池的作用是什么?
处理线程多并发,用一个数组保存线程,然后一直放着,如果没用就用条件变量让它休眠,如果加入一个新的任务就唤醒其中一个去执行这个任务。
Pthread_cond_signal和pthread_cond_broadcast的区别
Pthread_cond_signal表示唤醒睡眠线程中的一个【单播,可能按照优先级或者先来后到的原则】
Pthread_cond_boardcast表示唤醒所有睡眠线程【广播】
线程有几种状态?进程又有几种状态?
线程:
进程:
TCP三次握手和四次挥手及各自的状态?
三次握手:
CLOSE LISTEN
SYN_SENT
SYN_RCVD
ESTABLISHED
ESTABLISHED
四次挥手:
FIN_WAIT1
CLOSE_WAIT
FIN_WAIT2
LAST_ACK
TIME_WAIT
CLOSE
CLOSE
TCP如果两次握手会出什么问题?那三次握手又会造成什么问题?有什么好的解决方法没?
两次握手:客户端发送的连接请求可能在网络中滞留了,如果没有三次握手,可能会再次创建一个连接。
三次握手:引起SYN flood
不断发送同步报文段会因为传输控制模块TCB【处于半连接状态】从而消耗服务器资源
(1)【处理连接和半连接】定时释放监控系中无效的连接
(2)Syn cache技术【处理半连接状态】,接受到的SYN先不创建TCB,而是用一个hash表来表示,当前连接,如果接收到ACK然后再创建TCB
(3)Syn cookie技术【处理连接】通过一个cookie值来确定当前连接是否合法,合法就连接,一般的验证方法是,服务器接受到一个syn包,服务器通过syn产生一个cookie数据作为初始化序列,接收到ACK包时,序列-1就是得到的cookie,然后进行相应的验证。
TCP四次挥手为什么要有TIME_WAIT状态?为什么?
有两个原因:
(1)保证TCP协议全双工连接能够可靠关闭,直接关闭的话,如果服务器没有收到ACK,会重复发FIN。
(2)保证这次连接的重复数据从网络中消失,如果上次的socket和这次的socket处理的程序一样,就会导致这次连接把上次的数据加进来了。
死锁的原因?条件?如何预防?又如何避免?如何解除?
原因:系统资源不足;进程运行推进顺序不合适;资源分配不当
条件:互斥;不剥夺;循环等待;请求与保持
预防:破坏任意一个条件
避免:银行家算法
检测:资源分配图简化法
排序稳定的算法,你知道那些?
冒泡排序;插入排序;归并排序;基数排序
解决hash冲突的方法?
线性探测法;开链法;再哈希法;
C++分为内存分为哪几部分?
堆;栈;静态全局;常量;自由存储区
如果new申请内存失败了,如何去解决?如果让你实现一个new,你会怎么实现?
如果申请失败可以通过set_new_handler来进行处理。
实现:需要注意申请失败,如果相应的处理函数则调用,否则抛出bad_alloc异常
如何得到一个结构体内成员的偏移量?
进程与线程的区别?
(1)进程又自己的独立地址空间,线程没有
(2)进程是资源分配的最小单位,线程是CPU调度的最小单位
(3)进程和线程通信方式不同
(4)进程切换上下文开销大,线程开销小
(5)一个进程挂掉了不会影响其他进程,而线程挂掉了会影响其他线程
(6)对进程进程操作一般开销都比较大,对线程开销就小了
逐层打印二叉树?
用BFS队列
构造函数能不能虚函数?为什么?那拷贝构造函数能不能为虚函数?为什么?
不可以为虚函数,因为在调用构造函数时,虚表指针并没有在对象的内存空间中,必须要构造函数调用完成后才会形成虚表指针。
拷贝构造函数是构造函数所以理由同上。
析构函数能不能虚函数?为什么?
可以为析构函数,没有为什么
模板和实现可不可以不写在一个文件里面?为什么?
只能写在一个一个头文件中。
原因:多文件处理变为一个文件其实是通过链接器来实现的,所以如果用源文件来处理模板实现,会导致链接失效,最主要的原因还是在编译,编译器会暂时不处理模板类只有在实例化对象时才去处理,但是这就需要实现的代码了,如果放在其他文件的话,就会无法形成相应的类。
什么是RAII资源管理?
即资源获取就是初始化,利用对象生命周期来控制程序资源,简单来说就是通过局部对象来处理一些资源问题
为什么要字节对齐?
(1)有些特殊的CPU只能处理4倍开始的内存地址
(2)如果不是整倍数读取会导致读取多次
(3)数据总线为读取数据提供了基础
在成员函数中调用delete this会出现什么问题?对象还可以使用吗?
如果当前内存空间真正被释放了再次调用成员函数会报错,调用成员变量好像没有问题。
如果在构造函数中调用memset(this, 0, sizeof(*this))来初始化内存空间,有什么问题吗?
对于有虚函数和虚表存在的类,在进行memset后不能调用虚函数和虚基表继承而来的数据和函数
对一个数组而言,delete a和delete[] a有什么区别?为什么?
对于基础数据类型没有什么区别,对于对象delete值调用一次析构函数,delete[]才会析构所有的东西。
Dynamic_cast是如何实现运行时类型转换的?
如果有些虚函数的话,会到对应的虚表中的RTTI去查找对应的类型来判断可不可以进行相应的转换。
C语言调用C++语法函数怎么做?那C++调用C语法的函数怎么做?
使用extern “C”来产生C语言环境编译的程序供外部使用。
Extern “C”是什么意思?他有什么作用?
表示当前声明需要用C语言环境进行编译。
进程间的通信方式有哪些?线程间的通信方式呢?
进程:共享内存,消息队列传递,无名管道,有名管道,信号,套接字
线程:锁机制,信号量,信号
IO模型主要有哪些?
阻塞,非阻塞,IO多路复用,异步
阻塞和非阻塞?同步与异步的区别?
自己领悟
Select,poll和epoll的区别?为什么?
Select和poll缺点:(1)每次调用select都需要将fd集合从用户态拷贝到内核态(2)每一次调用select都需要在内核中遍历所有的fd(3)select支持的文件描述符太小,默认1024,poll没有限制
Epoll:使用红黑树来存储fd,同时每一次通过epoll__ctl来将fd加入内核中,同时通过双向列表来返回已经出发某一个事件的fd
手写如何通过一个结构体的成员变量得到一个结构体的地址?
Struct{char a[0];}的作用?有什么好处?
充当可变缓冲区的作用,同时char a[0]不占用内存空间。
如何判断两个浮点数相等?
需要考虑浮点误差
浮点数为什么会有误差?
因为二进制无法精准的表示十进制小数,0.3和0.2都无法完整的用二进制表示。
TCP的nagle算法和延迟ack,还有CORK呢?他们有什么好处?一起用会有什么效果?你觉得可以有什么改进?
nagle算法:防止网络中存在太多小包而造成网络拥塞
延迟ack:减少ACK包的频繁发送
CORK:将多个包变成一个包发送,提高网络利用率,使载荷率更大
不可一起使用
栈上分配内存和堆上分配内存有什么区别?
栈上:分配简单,只需要移动栈顶指针,不需要其他的处理
堆上:分配复杂,需要进行一定程度清理工作,同时是调用函数处理的。
变量的存储方式有哪些?
Auto,extern,register,static
线程私有和共享那些资源?进程私有和共享那些资源?
线程私有:线程栈,寄存器,程序寄存器
共享:堆,地址空间,全局变量,静态变量
进程私有:地址空间,堆,全局变量,栈,寄存器
共享:代码段,公共数据,进程目录,进程ID
什么是守护进程?如何查看守护进程?什么是僵尸进程?如何查看僵尸进程?
守护进程:一个生命周期长,并且控制终端,然后周期性执行某种任务的进程
查看守护进程:ps a敏感词>
僵尸进程:进程退出,但是占用资源没有被回收
查看僵尸进程:ps -ef|grep defunct
进程同步机制?
信号量;管程;
什么是信号?
进程间通信机制中唯一的异步通信机制
kill函数的每一个参数的作用?
Pid>0:发给ID为pid的进程
Pid=0:发给进程组所有的进程
Pid=-1:发给所有的进程
Pid<-1:发给指定进程组的进程
什么是协程?
用户态的轻量级线程,有自己的寄存器和栈
虚拟内存实现有哪几种方式?有什么意义?
三种:请求分页存储管理;请求分段存储管理;请求段页式存储管理