实习笔记五—-实习前参与的面试的一些总结
在2019年底参加了一些实习的面试,也把这些经历写入到实习笔记当中吧。
字节跳动一面 (1h)
- 各种类型,指针,数组的sizeof()(经历实习之后对这些非常熟悉了)
delete
和delete []
的区别- 以下的代码的执行行为:
int i = {}; int i = {int }; int i = {int i;}; bool AllocMem(char* p, int len) { p = malloc(len); return p != NULL; }
new
和malloc
的区别- 有序的
list
和vector
查找的复杂度 iterator
失效的情形
主要原因是迭代器失效的类型:
-
由于插入元素,使得容器元素整体“迁移”导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。
-
由于删除元素使得某些元素次序发生变化使得原本指向某元素的迭代器不再指向希望指向的元素。
见https://blog.csdn.net/weixin_41413441/article/details/81591656
- tcp三次握手的过程,两次握手和四次握手带来的后果
++i
和i++
的区别
算法题(牛客网现场写代码):
- 找出一个数组中没有出现的最小的正整数
思路:我现场使用排序的方法,复杂度为O(nlog(n)),不过如果使用bitmap或哈希等算法,复杂度可以达到O(n)。另外,在算法题目中,如果能够把所有的边界条件处理得非常好(例如不合法的输入情况),能够给面试官更高的印象分,这是面试官后来告诉我的,我当时没有做好这一点。
- 实现一个36进制加法。
字节跳动二面 (40min)
- 空类的大小
1(每个个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址,所以空类所占的内存大小是1个字节。空基类可以是0)
- 各种类的sizeof(成员函数,静态函数,虚函数)
成员函数和静态函数都不会增加类的大小,因为这两种函数的实现是编译器实现外部的针对这种类型的函数(可参考Titan API和《深度探索C++对象模型》一书),而虚函数则会增加sizeof,因为会产生一个虚表
- 虚表的大小是不是固定的
应该不是,32位和64位的虚表大小不一。
- 32位和64位的机器上内存对齐会不会有差别:会(sizeof还有很多奇怪的问题,想不起来了,确实情况很复杂)
- 内存泄露的问题如何解决:
有检测内存泄漏的工具,例如Mac OS上的intrument,Linux下的valgrind,以及MSVC中有关的宏均可以检测出是否有内存的泄露。而为了避免内存泄漏,在编码过程中,建议使用智能指针替代裸指针。
- 智能指针的实现原理:
引用计数。
- 智能指针是否是原子性的
当时没答上,后来查资料知道引用计数底层使用的是原子量,因此是引用计数是线程安全的。(这里似乎也有争议,见http://snf.github.io/2019/02/13/shared-ptr-optimization/)另外,智能指针指向的对象并非线程安全的。
- 有没有用过操作系统特定的API
当时回答的是没有。。。。。。不过实习的一段经历倒是用了一些posix的API,也算不上特别高级的用法吧。
-
如何以操作系统API的方式操作文件,启动线程
-
TCP/IP协议中,一个服务器最多可以连接多少客户端,一个客户端最多可以连接多少服务器(假设都是公网IP,不考虑NAT等问题,计算机的性能上也不存在瓶颈,IPV4)
此题我都猜的六万多。。。算是猜对了一半。对于服务端,不考虑ip地址分类等因素,最大tcp连接数约为2的32次方(ip数)×2的16次方(port数),也就是server端单机最大tcp连接数约为2的48次方。而对于客户端,网络通信过程中服务端监听一个固定的端口,客户端主动发起连接请求后要经过三次握手才能与服务器建立起一个TCP连接.客户端每次发起一个TCP连接时,系统会随机选取一个空闲的端口,该端口是独占的不能与其他TCP连接共享,因此理论上一台机器有多少空闲的端口,就能对外发起多少个TCP连接。根据TCP/IP协议,端口port使用16位无符号整数unsigned short来存储,因此本地端口一共有2^16=65536个,即0-65535,其中0~1023是预留端口,0有特殊含义不能使用,1024以下端口都是超级管理员用户(如root)才可以使用,因此就算使用root权限,一台机器最多能使用的端口也只有65535个。但是一台机器最多只能利用28232个端口。
见https://www.cnblogs.com/watchslowly/p/10967332.html
- 如何建立socket,如何实现轮询
在服务端:
- 调用
ServerSocket(int port)
创建一个server
端套接字,并绑定到指定端口上。 - 调用
accept()
监听连接请求,则接收连接,返回通信套接字(死循环等待) - 调用
Socket
类的getOutStream()
和getInputStream()
获取输入输出流,开始网络数据的发送和接收 - 关闭通信套接字
Socket.close()
在客户端就比较简单了:
- 调用
Socket()
创建一个流套接字,并连接至Server
端 - 调用
Socket
类的getOutputStream()
和getInputStream
获取输出流和输入流,开始网络数据的发送和接收。
实现轮询的方法:Linux上有select和epoll,Mac OS 上有kqueue,windows上有IOCP.select为O(n)复杂度,无差别轮询,遍历每一个io操作判断是否就绪,poll为O(n)复杂度,与select无本质差别,但没有最大连接数的限制。epoll的复杂度为O(1),事件驱动,event poll,每个事件关联上fd,io操作就绪时就会通知epoll. 其实本质上都是同步的IO,整个读写过程是阻塞的。
- http的请求格式和响应格式
请求:请求行,请求头部,空行,请求数据
响应:状态行,消息报头,空行,响应正文
详见https://www.cnblogs.com/qdhxhz/p/8468913.html
- http中有哪些header,有哪些http响应状态码
header太多了,不列举了。状态码大概可以依据首位数进行分类:
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
---|---|
2** | 成功,操作被成功接收并处理 |
3** | 重定向 |
4** | 客户端错误 |
5** | 服务器错误 |
-
好像还问了tcp长连接的问题,问题想不起来了。。。
-
一个TB级别的文件,内容为无数个以空格分隔的字符串,如何精确统计出字符串的种类个数。
因为是精确,所以直接用哈希会有问题,因为可能会发生哈希碰撞,当然碰撞后可以再加入链表。文件的内容很大,内存可能不够用,而直接使用硬盘作缓存速度会骤然下降。面试官一直给提示,最后我答出使用并行面试官点头,应该这个是可以接受的答案。不过后来才发现,使用MapReduce模型效率会更高,这个题就是解释MapReduce模型的一个经典例子。
- 算法题,牛客网现场写代码:将给定的一个全是数字的字符串分割为5段(5段均不能为空),在中间插入4个|,满足每段子字符串的数字不大于600,输出所有分割方法。
不多说了,递归就可以解决。如果用算法的语言描述,就是动态规划问题。
蓦然认知面试(现场面试,1h)
- 自己写过哪些程序
- 聊自己的太阳能无人机项目,包括太阳能无人机可能的运用场景
- 聊无人机动力优化系统的细节
- 写多态的一个例子 问多态的细节 包括多态的应用场景以及带来的好处
多态的好处:提高了代码的扩展性,使得代码易于维护,能够保持低耦合高聚合。(另外基类和继承类的写法也可以增强代码的复用性)
- shared_ptr如何实现指向对象的线程安全
这个最简单的方法我觉得就是加锁。
- 手写归并排序
大疆电话面试(20min)
- 自我介绍
- new和malloc区别
- vector和数组的区别
- 类和对象的区别
- 抽象类和虚表
- 成员函数和静态函数的区别
- 链表和哈希表
- 用qt做过什么
- 用qt做过哪些网络编程
- tcp和udp的区别
- udp中如何保证接收的数据的正确性
- 有哪些设计模式 讲讲优缺点
- 广度优先和深度优先
- 项目中遇到的最大困难以及是如何去解决的
当时没怎么做过编程的项目,没答上。。。
字节跳动三面(40min)
- 自我介绍
- 前两次面试的收获
- 自己C++的代码量
- C++和其他语言的区别,比如js
参见这个吧:https://blog.csdn.net/qq_34754747/article/details/104249829
- JIT是什么
即时编译(英语:Just-in-time compilation),又译及时编译、实时编译,动态编译的一种形式,是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态直译。静态编译的程序在执行前全部被翻译为机器码,而直译执行的则是一句一句边运行边翻译。
即时编译器则混合了这二者,一句一句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。相对于静态编译代码,即时编译的代码可以处理延迟绑定并增强安全性。
即时编译器有两种类型,一是字节码翻译,二是动态编译翻译。
相关讨论可以在知乎上搜索。
- 模板编程是什么
- 实现一个基于模板的vector 要求有成员函数push_back pop_back 以及赋值
- 用宏写取两数最大值的MAX函数
当时几乎没怎么写过宏,没有写出来。
#define MAX(a,b) (((a)>(b))?(a):(b))
- 宏是什么
- 指针和引用的区别 什么变量可以有指针不能有引用
可参见https://www.zhihu.com/question/37608201。指针可以是NULL,引用不像。
- 投硬币游戏 两人轮流投硬币 先取到正面的获胜 先投者获胜概率
三分之二。
- 实现prev_permutation算法
这个在侯捷的《STL源码剖析》一书中介绍了STL port的此算法实现原理:
首先,从最尾端开始往前寻找两个相邻元素,令第一元素为*i
,第二元素为*ii
,且满足*i<*ii
,找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i
的元素,令为*j
,交换i,j
元素,再将ii
之后的所有元素颠倒排列。
字节跳动HR面(20min)
- 职业规划
- 为什么选择字节跳动实习
- 描述大学里面自己典型的一天
- 大学里最有成就的一件事
- 有没有其他面试
- 自己有哪些圈子
- 我有哪些不足
- 别人对我的评价