又是一年春招季,我的某位友人去字节跳动应聘测试开发岗位,却在面试中被问了许许多多跟测试开发关联不大的问题。这些问题中,有一些问题我能回答出来,但更多的问题却是似是而非。趁着今天休息,我整理了一些面试题目和答案,供日后翻阅。
笔者水平有限,如有错误或疏漏欢迎指出。
(PS:面试官的面试题目往往跟简历内容关系很大,因此某些问题里涉及的知识可能是你完全没有学过,又不会写进简历里的)请说一下你对编译器和编译过程的理解,如果你们学校开设过编译原理必修课,请介绍一下这个课程的实验体系。
主观性很强的问题。可以回答得很简单,也可以很深入。
编译器:将源代码“翻译”成目标代码(多为二进制机器码)的程序。
编译过程:词法分析、语法分析、语义分析与中间代码生成、代码优化、生成目标代码。
普通的学生党答到这里应该就可以了,但如果更深层次也可以在编译过程中回答诸如(以C/CPP举例)“确定标准库与头文件的位置”、“头文件预编译”、“确定源码文件之间的依赖关系”等等。词法分析和语法分析的输出是什么?
词法分析的输出:Token
语法分析的输出:语法树你对语法树的理解是什么?请描述一个条件语句的语法树。
又是一个很宽泛的问题。
语法树:一种表达式/语句的语法推导的中间表示形式,树形结构。
之后还可以说一说抽象语法树之类的。
条件语句的语法树:if(a>b) a=a+b编译过程中如何解决二义性问题?
通过人为添加语法规则外的约束,比如规定运算符优先级。
或者直接重写等价的无二义性的文法。
来自友人的补充:
if-else这种二义性,是没办法通过改写文法消除的,一般是遵循最大吞噬原则(或者“最长匹配原则”)NFA和DFA是什么?它们有什么区别?它们在编译过程中如何应用?为什么用它们而不用别的工具?
NFA:不确定的有穷自动机。
DFA:确定的有穷自动机。
区别有大概这些:DFA一个输入只能得到一个状态的输出,而NFA可能得到的是一个输出状态集合;自动机的箭头上是否有空串(我真的只能想起来这些了)。
这两者都是Lex的识别器,在词法分析过程中起重要作用。
为什么不用别的工具:知识盲区。
友人的回答则比我能口胡的几句靠谱很多,他认为这是因为自动机比较好维护,并且因为自动节点暗含了分析过程的环境,插入报错和输出会更精确,而且现在有自动化程序,自动机可以用算法一键生成,不用手工。同时自动机不存在回溯的情况,if-else就可能存在。比如两种token可能拥有相同的头部,你按照某一种分析结果分析失败了,就只能回溯到token开头重新尝试, 自动机一旦分析失败,那就是真的有错。知道 flex 和 yacc 吗?它们分别是干什么用的?
在龙书中,对于Flex的描述似乎只有一句:“在本节中我们将介绍一个名为Lex的工具,在最近的实现中它也被称为Flex”。所以Flex和Lex的功能是相同的,都是作为词法分析器生成工具在被使用。
Yacc(Yet Another Compiler Compiler),是Unix/Linux上一个用来生成编译器的编译器。(知识盲区)C++是如何实现多态的?
重载、泛型、虚函数。C++的引用和指针有什么区别?
引用必须被初始化,但是指针可以先不赋值(之后再赋值)。
指针可以为空,引用不可以为空。
指针可以被重新赋值指向另一个不同的对象,但是引用则总是指向初始化时被确定的对象。Python的类和C++的类有什么不同?
这个问题感觉也很宽泛。
C++的类有public、private,Python的类没有。(Python类是不存在什么私有成员变量这种东西的,但是据说以单下划线开头的成员变量一般被认为成非公有,甚至还有保护等级更高的以双下划线开头的成员变量)
C++的类确定了就不能再添加成员变量,而Python可以。
C++的类是类,Python的类是对象(逃Python的类是如何实现多态的?
(Python中是没有重载的)
鸭子类型。Python想让一个对象能通过str()函数字符串化,应该怎么做?
这个问题看起来比较抽象,可能有些同学会一下子想到Python万物都是对象,那对一个int只要str()就行了。但实际上这里的意思是在打印类的实例对象时用到了什么方法。
答案是__str()__。你刚才提到__str()__,还有什么类似的函数吗?
__repr__(),__init()__(可以举的例子有很多)Python里的slice是做什么用的?
浅的回答就切片俩字,稍微拓展一点可以谈谈slice类中的参数(其实也不深)。对Linux了解吗?能说说Linux的文件系统吗?文件块是什么?
(第一问我就想直接回答:我了解个猴子)
Linux文件系统:Ext2->Ext3->Ext4
Linux中的一个文件由目录项,iNode和数据块组成。
目录项包括:文件名、iNode节点号
iNode包括:文件索引节点,存储了文件的基本信息(读写属性,所有者)和指向数据块的指针
数据块:真正存文件的地方
文件块是什么:我没有找到叫文件块的名词,疑似是“数据块”的误记。能说说Shell的工作原理吗?比如解释一下`ls`命令执行时都发生了什么?
Linux内核会建立一个进程去执行shell中的用户输入的命令,相当于一个方便使用者使用操作系统的接口。基本执行过程如下:
读取输入的命令行
分析命令,将其改造为系统调用execve()内部处理所要求的形式
fork一个子进程
父进程调用wait()等待子进程运行,子进程运行调用execve(),子进程根据命令名/文件名到目录中查找相关文件,查找到之后将它调入内存,再执行这个程序。
父进程等待子进程完成处理后结束wait(),等待用户输入新的命令。
ls的执行过程按照上边这个来说就好。再深入的我也不会了。能说说线程是什么吗?它有什么好处?
一个很“学院派”的问题。
线程是计算机CPU调度的最小单位,一般线程都在进程里,同一个进程下的线程共享进程的资源。
好处:无非是轻量、灵活、减小开销之类的。知道死锁吗?为什么会发生死锁?
又是一个“学院派”问题。
死锁是多个进程在运行时因为资源争夺而造成的一种互相阻塞的现象。可以举例哲学家就餐问题作为形象的例子(其实也不咋形象)。
为什么会发生死锁:
互斥、占有并等待,资源的不可抢占、循环等待。异步和同步有什么区别?
主要区别应该就是:同步在发出调用请求之后,一直等到系统的返回值或消息,必须得到回复才能执行下一步;异步是发出调用请求之后向系统委托一个异步过程,之后该干嘛干嘛。有返回值或消息了就用之前委托的异步过程来处理。知道HTTP协议吗?它的header结构描述一下?知道TCP协议吗?它的header结构描述一下?
这两个在计算机网络课程中都有提及,但是我不相信有非专业从业者能全文默写。
子网掩码是干什么用的?子网掩码最多有多少位?
给定IP地址结合子网掩码可以确定所在的子网地址。
32位的2进制数。计算机网络的底层传输是如何实现的?
模糊的问题,我猜可能是想问比特流。