面试
C/C++:
1.指针和引用的区别
指针:指针就是内存地址,指针变量是用来存放内存地址的变量.不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。
引用:引用不是新定义一个变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间.
区别:
- 初始化:引用在定义时必须初始化,指针则没有要求(尽量初始化,防止野指针)
- 引用在初始化引用一个实体后,就不能再引用其它实体,而指针可以在任意时候指向一个同类型实体
- 没有NULL引用,但是有nullptr指针
- 在sizeof中含义不同: 引用结果为引用类型的大小,但指针始终是地址空间,所占字节个数(32位平台占4个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但没有多级引用
- 访问实体的方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对安全
2.C++的特性
封装:将数据和行为(或功能)有机结合起来,形成一个整体。把数据和处理数据的操作结合形成类,数据和函数都是类的成员。增强安全性和简化编程。对外隐藏实现细节暴露公共接口。外部通过接口来调用。
特点:提高复用性,提高安全性
继承:继承就是A类被B类继承,A类为父类,B类为子类。B类继承Al类的所有公共和保护成员数据(属性)和成员函数(方法)。子类可以重新定义父类某些属性,重写父类的某些方法,即覆盖父类的某些属性和方法。使其获得与父类不同的功能。
特点:
- 减少重复代码,增加复用性。
- 让类与类之间产生关系,是多态的前提。
- 增加了类与类之间的耦合性
多态:一个接口多种实现状态。多态的出现大大提高了程序的扩展性。
静态多态:
- 在同一个作用域对函数进行重载(函数名相同,函数参数列表不同)。
- 对函数进行模板化,忽略数据类型强调数据操作
动态多态:
- 基于封装和继承的来实现的,多个子类对继承于一个父类的虚函数进行重写,来实现不同状态。
多态的体现:
- 父类引用或指针指向子类对象。
- 父类的引用或指针可以接受子类对象。
多态的前提:
- 必须存在父类与子类的继承关系。
- 父类中必须有虚函数。
- 子类必须重写父类的虚函数。
- 父类引用或指针指向子类对象。
3.堆和栈的区别
一个由C/C++编译的程序占用的内存分为以下几个部分 :
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(静态区)(static)— 全局变量和静态变量的存储是放在一块的,初始化的 全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统放。
4、文字常量区 — 常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区 — 存放函数体的二进制代码。
申请方式:
stack: 由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap: 需要程序员自己申请,并指明大小,在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = new char[10]; 但是注意p1、p2本身是在栈中的。
申请后系统的响应:
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程 序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
申请大小的限制:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
申请效率的比较:
栈 由系统自动分配,速度较快。但程序员是无法控制的。
堆 是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. 另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。
堆和栈中的存储内容:
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。 当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆: 一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。
4.静态编译和动态编译
动态编译的可执行文件需要附带一个的 动态链接库,在执行时,需要调用其对应动态链接库中的命令。所以其优点一方面是缩小了执行文件本身的体积,另一方面是加快了编译速度,节省了 系统资源。缺点一是哪怕是很简单的程序,只用到了链接库中的一两条命令,也需要附带一个相对庞大的链接库;二是如果其他计算机上没有安装对应的 运行库,则用动态编译的可执行文件就不能运行。
静态编译就是 编译器在编译可执行文件的时候,将可执行文件需要调用的对应动态链接库(.so)中的部分提取出来,链接到可执行文件中去,使可执行文件在运行的时候不依赖于动态链接库。所以其优缺点与 动态编译的可执行文件正好互补。
6.析构函数 虚析构 纯虚析构函数的区别和作用
多态使用时,如果子类中有属性开辟到 堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为 虚析构 或者 纯虚析构
虚析构和纯虚析构共性:
-
可以解决父类指针释放子类对象
-
都需要有具体的函数实现
虚析构和纯虚析构区别:
-
如果是纯虚析构,该类属于抽象类,无法实例化对象
操作系统:
1.进程和线程的区别
- 进程是资源分配单位,线程是CPU调度单位;
- 进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈;
- 线程同样具有就绪、阻塞和执行三种基本状态,同样具有状态之间的转换关系;
- 线程能减少并发执行的时间和空间开销:
- 线程的创建时间比进程短;
- 线程的终止时间比进程短;
- 同一进程内的线程切换时间比进程短;
- 由于同一进程的各线程间共享内存和文件资源,可直接进行不通 过内核的通信;
2.线程池如何实现
通过管理一个任务队列、线程队列,将主线程中用户提交任务到一任务队列中,空闲的线程将从任务队列中获取任务并执行,用户可以异步的获取提交任务的执行结果。
基本框架如下图所示。这里的任务调度执行策略为:任务队列无上限,同时执行任务的数量固定,有空闲线程时获取队列中的队头任务。
线程池的线程是复用的,线程池中的线程创建后不销毁,直到线程池关闭退出。每个线程创建后,循环执行从任务队列获取任务并执行。
线程池与任务队列之间需要匹配,是一个典型的消费者-生产者模型,需要解决资源访问冲突,并且保证任务为空时,线程应该等待(阻塞),即需要实现线程安全、有同步机制的任务队列。

3.线程池的同步机制
4.select、poll 和 epoll的区别
9.2 I/O 多路复用:select/poll/epoll | 小林coding (xiaolincoding.com)
5.什么时候会进行内核态和用户态的转换
用户空间:指的就是用户可以操作和访问的空间,这个空间通常存放我们用户自己写的数据等。
内核空间:是系统内核来操作的一块空间,这块空间里面存放系统内核的函数、接口等。
在用户空间下执行,我们把此时运行得程序的这种状态成为用户态,而当这段程序执行在内核的空间执行时,这种状态称为内核态。
用户态切换到内核态的3种方式:
a.系统调用
这是用户进程主动要求切换到内核态的一种方式,用户进程通过系统调用申请操作系统提供的服务程序完成工作。
b.异常
当CPU在执行运行在用户态的程序时,发现了某些事件不可知的异常,这是会触发由当前运行进程切换到处理此
异常的内核相关程序中,也就到了内核态,比如缺页异常(硬中断)。
c.外围设备的中断
当外围设备完成用户请求的操作之后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条将要执行的指令
转而去执行中断信号的处理程序,如果先执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了有
用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
6.定时器的实现原理
计算机网络:
1.tcp三次握手四次挥手
2.三次握手为什么不能是两次
3.四次挥手最后一次丢失了会怎样
4.udp如何实现可靠数据传输
5.http的字段
数据库:
1.索引的结构
2....
代码:
给一个序列,求出所有子串
浙公网安备 33010602011771号