第1章 面试的流程
第2章 面试需要的基础知识
第3章 高质量的代码
第4章 解决面试题的思路
第5章 优化时间和空间效率
第6章 面试中的各项能力
第7章 两个面试案例
7.1 案例一:(面试题49)把字符串转换成整数
面试官:看你简历上写的是精通C/C++语言,这两门语言你用了几年了?
应聘者:从大一算起的话,快六、七年了。
面试官:也是C/C++的老程序员了嘛(微笑),那先问一个C++的问题(递给应聘者一张A4纸,上面有一段打印的代码,如下面所示)。你能不能分析一下这段代码的输出?
应聘者:(看了一下代码,略作思考)n1是2,而n2是0。
面试官:为什么?
应聘者:在构造函数的初始化列表中,n2先被初始化为0,n2的值就是0了。接下来再用n2+2初始化n1,所以n1的值就是2。
[注:应聘者这个问题的回答是错误的,详见后面的面试官点评]
面试官:C++是按照在初始化列表中的顺序初始化成员变量的吗?
应聘者:(一脸困惑)不是这样吗?我不太清楚。
面试官心理:
对成员变量的初始化顺序完全没有概念就号称自己精通C++,也太言过其实了。算了,C++就不接着问了,看看你的编程能力。
面试官:没关系,我们换一个题目。能不能介绍一下C语言的库函数中atoi的作用?
应聘者:atoi用来把一个字符串转换成一个整数。比如输入字符串"123",它的输出是数字123。
面试官:对的。现在就请你写一个函数StrToInt,实现把字符串转换成整数这个功能。当然,不能使用atoi或者其他类似的库函数。你看有没有问题?
应聘者:(嘴角出现一丝自信的笑容)没有问题。
应聘者马上开始在白纸上写出了如下代码:
应聘者:(放下笔)我已经写好了。
面试官心理:
我出的题目有这么简单吗?你也太小看我了。
面试官:这么快?(稍微看了看代码)你觉得这代码有没有问题?仔细检查一下看看。
应聘者:(从头开始读代码)哦,不好意思,忘了检查字符串是空指针的情况。
应聘者拿起笔,在原来代码上添加两行新的代码。修改之后的代码如下:
面试官:改好了?(看了一下新的代码)当字符串为空的时候,你的返回是0。如果输入的字符串是"0"的时候,返回是什么?
应聘者:也是0。
面试官:两种情况都得到返回值0,那么当这个函数的调用者得到返回值0的时候,他怎么知道是哪种情况?
应聘者:(脸上表情有些困惑)不知道。
面试官:你知道atoi是怎么区分的吗?
应聘者:(努力回忆,有些慌张)不记得了。
面试官:atoi是通过一个全局变量来区分的。如果是非法输入,返回0并把这个全局变量设为一个特殊标记。如果输入是"0",则返回0,不会设置全局变量。这样当atoi的调用者得到返回值0的时候,可以通过检查全局变量得知输入究竟是非法输入还是字符串"0"。
应聘者:哦。(拿起笔准备写代码)我马上修改。
面试官:等一下,除了空字符串之外,还有没有可能有其他类型的非法输入?
应聘者:(陷入思考,额头上出现汗珠)如果字符串中含有'0'到'9'之外的字符,那么这样的输入也是非法的。
面试官:所有'0'到'9'之外的字符都是非法的吗?
应聘者:加号和减号应该也是合法的输入字符。
面试官:对的。先好好想想,想清楚了再开始写代码。
应聘者思考几分钟之后,写下了如下代码:
面试官:(看到应聘者写完了)能不能简要地解释一下你的代码?
应聘者:我定义了一个全局变量g_Status来标记是不是遇到了非法输入。如果输入的字符串指针是空指针,则标记该全局变量然后直接返回。接下来我开始遍历字符串中的所有字符。由于正负号只有可能出现在字符串的第一个字符,我们先处理字符串的第一个字符。如果第一个字符是符号,则标记当前的数字是负数,并在最后确保返回值是负数。在处理后续字符时,当遇到'0'到'9'之外的字符时,终止遍历。如果遇到了数字,则把数值累加上去。
面试官心理:
这段代码已经写得不错,你的编程能力看起来还不错,只是编程的习惯不太好,不会在编码之前想好可能有哪些输入,从而在代码中留下太多的漏洞。这次修改的几个问题都是我已经提醒你的,没有提醒的你自己没有找出一个。
面试官:不错。觉得功能上还有什么遗漏吗?
应聘者:还有遗漏?(思索良久)要不要考虑溢出?
面试官:你觉得呢?如果输入的是一个空字符串"",你觉得应该输出什么?
应聘者:""不是个数字,我想应该是返回0,同时把g_nStatus设为非法输入。
面试官:那你能分析一下你现在的输出是什么吗?
应聘者:(紧张,声音有些发抖)好像返回值是0,但没有设置g_nStatus为非法输入?
面试官:嗯。我们再考虑一些有意思的输入,比如输入的字符串只有一个正号或者负号,你期待的输出是什么?
应聘者:如果只有一个正号或者负号,后面没有跟着数字,我想也不是有效的输入。(开始分析代码)我的返回值是0,但不会设置g_nStatus。
面试官:由于时间也差不多了,已经没有时间给你再做修改了。我的问题问完了,你有什么问题需要问我的吗?
应聘者:你们公司工资待遇怎么样?
面试官:你的期望值是多少呢?
应聘者:我有不少同学的月薪税前超过8000,我不想低于他们。
面试官心理:
我不是HR,别和我谈工资。
面试官:我们公司由人事部门统一确定应届毕业生的工资,所以你的这个问题我不能直接回答,不过你的期望值我倒可以转告HR。
应聘者:好的,谢谢。
面试官:还有其他问题吗?
应聘者:没有了。
面试官:那这轮面试就到这里结束吧。
面试官点评:
这名应聘者在简历中写他精通C/C++,本来我对他的表现是充满了期待的。但在他回答错了第一个C++的语法题之后,他给我留下的印象就不是很好了。这就是希望越大失望越大吧。实际上,构造函数的初始化列表是C++中经常使用的一个概念。在C++中,成员变量的初始化顺序只与它们在类中声明的顺序有关,而与在初始化列表中的顺序无关。在前面的问题中,n1先于n2被声明,因此n1也会在n2之前被初始化,所以我们先会用n2+2去初始化n1。由于n2这个时候还没有被初始化,因此它的值是随机的。用此时的n2加上2去初始化n1,n1的值只是一个随机值。接下来再用0初始化n2,因此最终n2的值是0。
接下来是要求应聘者把一个字符串转换成整数,这看起来是道很简单的题目,实现其基本功能,大部分人都能用10行之内的代码解决。可是,当我们要把很多特殊情况即测试用例都考虑进去,却不是一件容易的事情。解决数值转换问题本身不难,但我希望在写转换数值的代码之前,应聘者至少能把空指针NULL、空字符串""、正负号、溢出等方方面面的测试用例都考虑到,并在写代码的时候对这些特殊的输入都定义好合理的输出。当然,这些输出并不一定要和atoi完全保持一致,但必须要有显式的说明,和面试官沟通好。
这个应聘者最大的问题就是还没有养成在写代码之前考虑所有可能的测试用例的习惯,逻辑不够严谨,因此一开始的代码只处理了最基本的数值转换。后来我每次提醒他一处特殊的测试用例之后,他改一处代码。尽管他已经做了两次修改,但仍然有不少很明显的漏洞,特殊输入空字符串"",边界条件比如最大的正整数与最小的负整数等。由于这道题思路本身不难,因此我希望他能把问题考虑得尽可能周到,代码尽量写完整。下面是参考代码:
在前面的代码中,把空字符串""和只有一个正号或者负号的情况都考虑到了。同时正整数的最大值是0x7FFF FFFF,最小的负整数是0x8000 0000,因此我们需要分两种情况来分别判断整数是否发生上溢出或者下溢出。
最后他在提问环节给我留下的印象不是很好。他只有一个问题,是关于薪水方面。是不是反映出他找工作仅仅关心工资?通常只关心工资待遇的员工是非常容易流失的,而且他把期望值设在8000的唯一理由是他有同学的工资超过这个数。他对自己有没有一个定位?
虽然从他后来改写代码的过程来看,他的编程能力还是不错的,但我担心以他现在的编程习惯,由于没有一个全面的考虑,他写出的代码将会漏洞百出,鲁棒性也得不到保证。总的来说,我的意见是我们不能录取这名应聘者。
源代码:
本题完整的源代码详见49_StringToInt项目。
测试用例:
- 功能测试(输入的字符串表示正数、负数和0)。
- 边界值测试(最大的正整数、最小的负整数)。
- 特殊输入测试(输入字符串为NULL指针、输入字符串为空字符串、输入的字符串中有非数字字符等)。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论