如果你是一个C++面试官,你会问哪些问题?

写在前面的话

我在今年出版了一本书《C++ 服务器开发精髓》,在这本书凝聚了我从客户端到服务器、从 Windows 到 Linux 的十多年的经验总结,你还将从本书中系统地学习到 C++ 开发编译调试完整技术链、多线程编程技术、精心凝炼的20多个网络编程重难点知识、网络故障排查与定位知识、如何设计可兼容可扩展的通信协议、如何设计高性能网络框架、如何设计高性能服务框架、如何开发服务常用组件等知识。

正文

先交代下背景:坐标上海,做技术开发。

一、那些求职 C++ 岗位的日子

几年前,我找 C++ 开发的工作,在三个月时间内,面了数家公司的 C++ 开发岗位,它们包括腾讯、百度、阿里的蚂蚁金服和国际支付宝部门(两个部门,两次面试)、饿了么、爱奇艺、360、携程网、京东、华为、bilibili、上海黄金交易所、东方财富网、zilliz、掌门集团(做无线万能钥匙的那一家)、喜马拉雅听书、UCLOUD、峰果网络、华尔街见闻、万得财经、汇正财经、逗屋网络、朝阳永续等公司,当然还有数家小规模的公司或创业公司吧。

二、求职的这些公司问了啥?

为了避免引起不必要的纠纷,下面我就不说具体的公司名称了。

总体可以分为几类:

(一)、以百度、爱奇艺等大厂,无论是不是 C++ 开发,都会以算法和数据结构为主。

常见的算法与数据结构题目有

1. 快速排序(包括算法步骤、平均算法复杂度、最好和最坏的情形)。

2. 写二分查找算法。

很多公司不会直接让你写二分查找算法,而是结合一个具体场景来提问,然后需要你自己联想到二分查找,比如求一个数的平方根。

3. 链表。

常见的面试题有写一个链表中删除一个节点的算法、单链表倒转、两个链表找相交的部分。

4. 自己实现一些基础的函数,例如strcpy / memcpy / memmov / atoi。

这些必须完全无误且高效地写出来,比如你的实现中有动态分配堆内存,那么这道题目就算答错。

第 3 点和第 4 点的关键点一般还会考察你的代码风格、对边界条件的处理,比如判断指针是否为空,千万不要故意不考虑这种情形,即使你知道也不行,只要你不写,一般面试官就认为你的思路不周详,代码不健壮;再比如,单链表的倒转,最后的返回值肯定是倒转后的链表头结点,这样才能引用一个链表,这些都是面试官想考虑的重点。

5. 哈希表。

对哈希表的细节要求很高,比如哈希表的冲突检测、哈希函数常用实现、算法复杂度;比如百度二面就让我写一个哈希表插入元素算法,元素类型是任意类型。

6. AVL 树和 B 树的概念、细节。

例如会问 mysql 数据库的索引的实现原理,基本上就等于问你 B 树了。

7. 红黑树。

这个是常问的一个数据结构,包括红黑树的定义、平均算法复杂度、最好最坏情况下的算法复杂度、左旋右旋、颜色变换。面试官常见的算法套路有:

面试官:你熟悉 C++ 的 stl 吗?

你:熟悉。

面试官:ok,stl 的 map 用过吧?

你:用过。

面试官:ok,那 map 是如何实现的?

你:红黑树。

面试官:ok,那什么是红黑树?

(这样提问,红黑树问题就正式开始了。)

(二)、以饿了么、bilibli、喜马拉雅、360、携程等为代表的,兼顾算法数据结构和其他开发技术。

算法和数据结构部分上文提过了,下面提一下其他技术,大致包括以下内容:

  1. C/C++ 语言部分

第一类是基础的 C++ 问题,常见的有:

(1) C++ 的继承体系中 virtual 关键字的作用(如继承关系中析构函数为什么要声明成 virtual 函数,如果不声明为 virtual 会有什么影响)

在涉及到父子类时构造与析构函数的执行顺序、多重继承时类的成员列表在地址空间的排列;

(2)static 关键字的作用,static_cast / reinterpret_cast / dynamic_cast 等几个转换符的使用场景;

(3)虚表的布局,尤其是菱形继承(B 和 C 继承 A,D 继承 B 和 C)时每个对象的空间结构分布,例如 问 D 有几份虚表,D 中 B 和 C 的成员空间排布;

(4)C++11/14/17 新标准的一些知识点:

  • auto 关键字

  • for-each 循环

  • 右值及移动构造函数 + std::forward + std::move + stl 容器新增的 emplace_back() 方法

  • std::thread 库 + 线程同步技术库 std::mutex/std::condition_variable/std::lock_guard 等

  • std::chrono 库

  • 智能指针系列(std::shared_ptr/std::unique_ptr/std::weak_ptr)(智能

  • 指针的实现原理一定要知道,最好是自己实现过)

  • lamda表达式

  • std::bind/std::function

  • 其他的就是一些关键字的用法(override、final、delete)

C++11/14 网上的资料已经很多了,C++17 的资料不多,重头戏还是 C++11 引入的各种实用特性,这就给读者推荐一本我读过的:

  • 《深入理解 C++11:C++11 新特性解析与应用》

  • 《深入应用 C++11:代码优化与工程级应用》

  • 《C++17 完全指南》

  • 《Cpp 17 in Detail》

这里网络上也有人分享出来,下载链接:

链接: https://pan.baidu.com/s/1xVuBcfm0qMvhHsMSAXcA4w 密码: g4iy

建议购买正版哦。

2. 网络编程问题

  • 协议栈的层级关系

  • tcp/udp 的区别和适用场景;

  • 三次握手和四次挥手的【细节】,注意我说的是细节,比如 CLOSE_WAIT 和 TIME_WAIT 状态(bilibili 问了这样一个问题,你可以感受一下:A 与 B 建立了正常连接后,从未相互发过数据,这个时候 B 突然机器重启,问 A 此时的 tcp 状态处于什么状态?如何消除服务器程序中的这个状态?

  • 万得问过流量拥塞和控制机制

  • 腾讯问过tcp和ip包头常见有哪些字段)

  • 东方财富网问了阻塞和非阻塞 socket 在 send、recv 函数上的行为表现

  • 异步 connect 函数的写法

  • select 函数的用法

  • epoll 模型,基本上只要问到 epoll,必问 epoll 的水平模式和边缘模式的区别

  • 一些 socket 选项的用法

  • nagle/keepalive/linger等选项的区别

  • 通信协议如何设计避免粘包

  • http 协议的格式、GET 和 POST 方法的区别

  • Windows 用户可能会问到完成端口模型(IOCP)

3. 操作系统原理性的东西

  • 比如上海黄金交易所、喜马拉雅听书问了 Linux 下 elf 文件的节结构,映射到进程地址空间后,分别对应哪些段,相关的问题还有,全局变量、静态存储在进程地址空间的哪里;

  • 堆和栈的区别,栈的结构,栈的细节一点要搞的特别清楚,因为一些对技术要求比较高的公司会问的比较深入,例如京东的一面是让我先写一个从 1 加到 100 的求和函数,然后让我写出这个函数的汇编代码,如果你对栈的结构(如函数参数入栈顺序、函数局部变量在栈中的布局、栈帧指针和栈顶指针位置)不熟悉的话,这题目就无法答对了;栈的问题,可能会以常见的函数调用方式来提问,常见的函数调用有如下 __cdecl/__stdcall/__thiscall/__fastcall 的区别,比如像 printf 这样具有不定参数的函数为什么不能使用 __stdcall;

  • 饿了么二面问了操作系统的保护模式实模式,中断向量表,Linux 下的 CAS。

以上这些问题的答案,《程序员的自我修养:链接、装载与库》这本程序员必读书中都有。感谢某位网友的分享:

链接: https://pan.baidu.com/s/1CPv6khHh3ad93w-XN0YXdA 密码: 8dbu

  • 还有就是进程和线程的联系与区别,问的最多的就是线程之间的一些同步技术,如互斥体、信号量、条件变量等(Windows 上还有事件、临界区等),这些东西你必须熟悉到具体的 API 函数使用的层面上来,从另外一个角度来说,这是咱们实际工作中编码最常用的东西,如果你连这个都不能熟练使用,那么你肯定不是一个合格的开发者;这类问题还可以引申为什么是死锁、如何避免死锁;进程之间通信的常用技术也需要掌握,常用的通信方式(Linux 下)有共享内存、匿名和具名管道、socket、消息队列等等,管道和 socket 是两个必须深入掌握的考察点(与上面网络通信有点重复);

  • Linux 系统下可能还会问什么是 daemon 进程,如何产生 daemo 进程,什么是僵尸进程,僵尸进程如何产生和消除(bilibili 问过)。

4. 项目经验和开源技术

  • 问的比较多的是 redis;

  • 网络库 libevent;

  • 数据库如 mysql 的一些东西;

  • 这个一般不做硬性要求,但是这里必须强调的就是 Redis,熟练使用 Redis 甚至研究过 Redis 源码,Redis 现在是对做 C++ 后台开发的技术硬性要求。

基于 Redis 的面试题既可以聊算法与数据结构,也可以聊网络框架等等一类东西。

我面试的公司中基本上百分之九十以上都问到了 redis,只是深浅不一而已,比如喜马拉雅问了 Redis 的数据存储结构、rehash;bilibili 问了 redis 的事务与集群。

(三)、只问一些做过的业务或者项目经验。

这类公司他们招人其实对技术要求不高(资深及主管级开发除外),只要你过往的项目与当前应聘职位匹配,可以过来直接上手干活就可以了,

当然薪资也就不会给很多。比如游戏公司会关心你是否有某某类型的游戏开发经验、股票类公司会关心你是否有过证券或者交易系统的开发经验等。我的建议是,对于这类公司,能去的话可以去,不能去的话就当积累面试经验。

业务开发哪里都能找到,真正的重视技术的公司,应该是广大做技术尤其是初中级开发的朋友应该优先关心的事情。

我分享一下我的学习书单,希望对你有帮助:

三、如今作为 C++ 面试官我会问哪些问题?

先贴一份前段时间一份 C++ 面试记录,读者可以感受一下:

1. A机器的进程给B机器的进程发送数据,经历哪些网络层?如何找到目标进程? 基本答出来了。

2. 如何解决粘包和半包问题?实际写过这方面的网络通信程序吗? 答得不是很清楚。未写过。

3. 对于http协议,如何判断当前的数据是否足够一个完整的http数据包? 面试者答的由TCP层保证,答得不对。读者的实践经历写了实现一个简易Web服务器,未回答出来如何解析http数据包。

4. http GET请求与POST请求的,网页源码的html文件的源码属于http包头还是包体问题? 基本答出来了。

5. select函数的用法 基本未答出来。

6. epoll模型的水平模式和边缘模式有什么区别? 说不清楚,与简历中描述的不符合。

7. 什么是reactor模型?什么是proactor模型? 基本答出来了。

8. 进程与线程的区别?一个线程因内存问题而退出,是否会导致整个进程退出? 一半说的对,一半说的不对。

9. 多线程之间同步用过哪些锁?实际写过这个代码?哪些情形会造成死锁? 基本答不出来。 10. Redis常用的数据类型有哪些? 说不完整。 11. 设计一个表结构高效地存储一篇帖子下面的评论以及评论的回复。 写出来。

总结起来,作为 C++ 面试官,对于工作年限不长的同学,会从如下几个方面考察:

  • 算法与数据结构

  • C/C++ 语言本身的内容

  • 操作系统原理

  • 多线程编程

  • 计算机网络

  • 数据库知识

四、面试者如何学习如何准备?

C/C++ 这门语言与其他高级语言不同,它是离操作系统较近的语言。所以学好 C/C++ 体系的技术栈必须结合操作系统的运行机制来学习。展开来说,就是你必须掌握操作系统层面的几大基础知识,他们是汇编、编译链接与运行时体系、狭义的操作系统原理、多线程、网络编程。

第一个基础知识是汇编,我们学习汇编不是一定要用汇编来写代码,就像我们学习 C/C++ 也不一定单纯为了面试和找工作。

对于 C/C++ 的同学来说,汇编是建议一定要掌握的,只有这样,你才能在书写 C++ 代码的时候,清楚地知道你的每一行C++代码背后对应着什么样的机器指令,if/for/while 等基本程序结构如何实现的,函数的返回值如何返回的,为什么整型变量的数学运算不是原子的,最终你知道如何书写代码才能做到效率最高。掌握了汇编,你可以明白,在 C++ 中,一个栈对象从构造到析构,其整个生命周期里,开发者的代码、编译器和操作系统分别做了什么。掌握了汇编,你可以理解函数调用是如何实现的,你可以理解函数的几种调用方法,为什么printf这样的函数其调用方式不能是 __stdcall,而必须是 __cdecl。掌握了汇编,你就能明白为什么一个类对象增加一个方法不会增加其实际占的内存空间。

第二个基础知识是编译、链接与运行时体系知识。作为一个开发者,要清楚地知道我们写的 C/C++ 程序是如何通过预处理、编译与链接等步骤最终变成可执行的二进制文件,操作系统如何识别一个文件为可执行文件,一个可执行文件包含什么内容,执行时如何加载到进程的地址空间,程序的每一个变量和数据位于进程地址空间的什么位置,如何引用到。一个进程的地址空间有些什么内容,各段地址分布着什么内容,为什么读写空指针或者野指针会有内存问题。一个进程如何装在各个 so 或 dll 文件的,这些文件被加载到进程地址空间的什么位置,如何被执行,数据如何被交换。

第三个基础知识是狭义的操作系统原理。这里加上“狭义”二字是因为从广义上来讲,以上所说的内容都是操作系统原理的范畴。狭义的操作系统原理这里包括操作系统如何管理进程与线程,虚拟内存与物理内存之间的对应关系,何为内存映射文件,进程之间如何通信等等。

第四个基础知识是多线程知识。严格来说,这点已经包括在第三点之中了,我之所以将其单独列出来,是因为多线程编程是我们做应用服务最常用的技术之一。最近面试过几个学历非常好的同学,对于一个进程中如果某个线程因为内存问题而退出,是否会导致整个进程退出的问题答不好,实在不应该。多线程知识其实不难学,立足于理解与实践而不是应付面试,可以学的很好。无论是 Windows 还是 Linux 操作系统,操作系统提供的线程同步对象就那么几种,Windows 常用的有临界区(关键端)、Event、互斥体、信号量等,Linux 有互斥体、信号量、读写锁、条件变量,这些知识点学过则会,不学则不会。这些线程同步原语花上几天就能搞得清楚,大多数同学不是学不会,而是不愿意学,但是偏偏喜欢在简历上写上自己熟悉多线程编程。面试的时候,被问到条件变量的虚假唤醒机制都说不清楚,非要说自己用过条件变量。这是一些同学犯的很低级的错误,如果真用过条件变量,如果不知道虚假唤醒机制,那一定写的代码是不对的。市场上目前没有任何一本图书对以上知识形成体系的介绍,当然,我的本书填补了这一空缺,你将从本书中获得从进程与线程的关系,再到常用的线程同步原语的区别与使用场景,再到线程池以及基于生产者消费者模型的消息队列,以及对协程思想介绍的相关知识。

掌握了常见的多线程同步原语之后,接下来可以找一些带多线程的项目去学习一下,不管是否带 UI 的都行。我推荐的一种方式是,使用 gdb 或者 Visual Studio 调试器将你需要学习的多线程程序中断下来,在多线程面板,看看这个进程一共有多少个正在运行的线程,分析每个线程的作用,然后研究下这些线程在何时何地创建的,为什么需要创建新的线程。尝试爱过几个人,面对爱情你会诚实很多;尝试研究几个多线程项目,面对多线程你会熟练许多。

第五个是网络编程,直白地说就是 Socket 编程。操作系统层面提供的 API 会在相当长的时间内保持接口不变,一旦学成,终生受用。理解和掌握常用的基础 socket API 不仅可以最大化地去定制各种网络通信框架,更不用说使用市面上流行的网络通信库了,最重要的是,它会是你排查各种网络疑难杂症坚实的技术保障。操作系统层面提供的网络模型就那么几种,无论像 Java/Go/Python 等语言如何封装,作为技术的源头,我们有什么理由不去掌握它呢?市面上关于网络编程的书很多,我在书中结合我这些年的工作经验总结了二十几个网络编程中的重点和难点,现在全部交给你。

以上是基于 C++ 技术栈来说,并没有包括算法与数据结构、数据库等方面的基本功,但是这些额外的也是应该需要掌握的。掌握了如上所说的,你就达到了一个熟练工阶段。

贴一张示意图:

五、推荐的书单

我精心整理了一份给 C/C++ 开发者的书单(数量不多),推荐给大家:

我在知乎上也做了几个关于 C++ 求职与面试的 Live 分享,有兴趣的小伙伴可以关注一下:

如何求职 C++ 后端开发岗位

轻松搞定技术面试中常见的网络通信问题

C++高性能服务器网络框架设计的细节

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值