ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

系统软件开发笔试核心考点:C++基础、操作系统与算法刷题策略

系统软件开发笔试核心考点:C++基础、操作系统与算法刷题策略 1. 一道笔试题背后的岗位真相系统软件开发到底考什么先说个扎心的结论大部分人刷题准备校招方向从一开始就错了。看到“小米2019秋招系统软件开发笔试题B”这种标题很多人的第一反应是赶紧找原题、背答案、刷LeetCode。但如果你真的把系统软件开发当成“算法岗”来准备笔试这一关大概率过不了。为什么因为系统软件开发这个岗位核心考察的不是你会不会写红黑树、能不能默写快排而是三件事基础扎实程度、系统理解深度、工程实现能力。一份B卷里算法题当然有但它只是其中一个模块。真正拉开差距的是那些看起来“很基础”的题目——C里一个空类的大小、一个volatile关键字的行为、一段并发代码的竞态条件这些才是系统软件工程师日常吃饭的本事。我见过太多同学LeetCode刷了三百题问起“为什么TCP挥手要四次”支支吾吾让手写一个线程池写出个半成品。这类人放在系统软件开发岗的笔试里往往栽在那些“最不起眼”的题上。反过来说如果你基础扎实哪怕算法题的AC率只有六成整体成绩依然可能排在前面——因为系统软件开发的笔试题考的是“你有没有资格做系统软件”而不是“你是不是个刷题机器”。这篇文章我想借“小米2019秋招系统软件开发笔试题B”这个具体场景聊透系统软件开发岗笔试背后的能力模型、备考方法和避坑思路。无论你手里拿到的是哪一年的题、哪个厂的B卷底层逻辑大差不差。1.1 从B卷看能力模型基础、系统、代码三足鼎立先把话挑明系统软件开发岗的笔试题一般由三大部分构成。第一部分是语言基础。C/C是绝对主力偶尔会有岗位细分到Java或Go但小米这种做系统层和底层优化的团队C几乎必考。这一块考的不是语法背诵而是语言机制的内功指针和引用的本质区别、虚函数和虚表的工作方式、内存对齐规则、C11/14的移动语义和完美转发、智能指针的实现原理。题目形式多是选择题加简答题选择题看着简单其实每个选项都是一层伪装考的是你是不是真的懂。第二部分是操作系统与Linux。进程和线程的区别只是开胃菜真正拉分的是这些虚拟内存到物理内存的映射过程、malloc在底层做了什么、死锁的四个必要条件怎么用代码触发、多线程并发时atomic和mutex的区别、Linux下进程间通信方式各自的适用场景。有些题会直接给你一段代码问它输出什么而这段代码里藏着栈帧、局部变量生命周期、static和const的组合规则——这种题本质上是把语言机制和操作系统揉在一起考。第三部分是数据结构、算法与网络。算法题的难度一般卡在LeetCode Medium偏上不会出Hard压轴题。但题目风格和纯算法岗有明显区别更偏重工程场景比如“海量日志中找高频IP”“实现一个支持过期时间的LRU Cache”“设计一个线程安全的单例”。网络部分则是TCP/UDP、HTTP、Socket编程的经典问题不会考太偏的东西。这三块在B卷里的权重大致是语言基础30%、操作系统30%、算法与数据结构25%、网络15%。当然每个岗位会微调但这个比例非常接近系统软件开发的真实工作内容写的是C、跑在Linux上、关心并发和内存、离不开网络。1.2 为什么校招笔试偏爱“老八股”题目很多同学会吐槽这些题目太老了什么虚函数、什么死锁条件工作了根本用不到吧这个想法我特别理解但它只对了一半。先说不虚幻的部分虚函数表、内存布局、栈帧这些东西你在平常写业务代码时可能确实碰不到。但系统软件的日常就是跟这些概念打交道——你写一个网络框架要对接不同的协议实现类虚函数的动态绑定决定了整个扩展方式你排查线上进程OOM不理解虚拟内存和页表连从哪里下手都不知道。这类概念不是“过时”而是底层到了极致以至于你意识不到它在背后运行。至于另一半校招筛选的核心逻辑是“用最低成本找到具备系统思维的人”。笔试题目高度标准化背后是几十万人里筛出聪明、扎实、有潜力的人。虚拟内存、线程同步、指针操作这些知识短期背不下来也没法靠一两周突击出效果——所以它们成了最有效的筛选器。想清楚这一点备考思路就清晰了不要指望靠押题或背诵过笔试而是要趁准备周期把自己真正“补”成一名系统软件开发者该有的样子。这也是为什么我特别反对直接找笔试题答案来背的原因——就算你把B卷的答案全背下来明年换成C卷D卷你依然不会。2. 核心考点逐个拆解C/C与操作系统的主战场2.1 C/C基础不是语法过关就行C/C这块B卷选择题的杀伤力相当大。举几个几乎每年都会出现的题目类型。第一类“sizeof与strlen”。看似简单但因为C有继承、虚函数、static成员、空类优化这些机制sizeof问题能玩出花儿。比如一个空类sizeof是多少很多人答1对因为编译器要给空类分配一个字节以示不同对象有不同地址。但如果这个空类里有虚函数呢答案变成8或4取决于平台指针大小因为存在虚函数指针。如果派生类继承了一个带虚函数的基类又加了自己的虚函数呢虚表指针只有一份大小不变。这种题考察的不是记不记得住数字而是对对象内存布局的理解。第二类“const、static、volatile的语义”。volatile是重灾区。我面试别人的时候经常问“一个被volatile修饰的变量多线程下安全吗”至少六成人会答“安全”。正确理解是volatile只是告诉编译器不要对这个变量的访问做优化比如缓存到寄存器但如果多个线程同时写它那依然是数据竞争该用原子变量还得用原子变量。这就是笔试喜欢考的点——看着考一个关键字实际上考的是整个并发模型。第三类“指针和引用的区别”。这道题几乎是所有C试卷的保留节目。入门教材会告诉你“引用是变量的别名”听起来很轻巧。但笔试想让你答出来的是引用不能重新绑定、引用不能为null、引用不是一个独立对象sizeof引用得到的是原对象大小、引用在底层实现上是一个指针但语言层面屏蔽了指针的灵活性。以及最关键的一条函数参数用引用而不是指针能避免指针判空和重复解引用的繁琐这是C风格上区别于C的重要一点。C这块的复习建议我不推荐一上来就刷题。先把这些书啃透《C Primer》重点看第6、12、13、15章、《Effective C》条款5到条款12全是笔试素材、《深度探索C对象模型》这本书看完sizeof、布局、虚表这类题基本是送分。不用追求一遍全懂但你要保证“看到题目能联想到考点对应的条款或章节”这个联想能力在笔试现场非常救命。还有个小提示B卷的C题目往往会有意识考察“C11/14/17新特性”。如果你还在用C98的老语法回答问题比如还在手动管理裸指针而不提move语义、不知道auto和智能指针分数会很吃亏。时代变了校招题也在变。2.2 操作系统与Linux面试官的隐形过滤器操作系统这块B卷的大题和简答比选择题更能暴露水平。这里我挑三个最高频的方向展开说。**一个是进程与线程。**笔试最常出现的坑是“问区别别只答一句话”。光说“线程共享地址空间进程是独立地址空间”不够。要能答出以下层次调度实体上Linux里进程和线程都用task_struct表示线程本质上是“轻量级进程”资源共享上线程共享代码段、数据段、堆、打开的文件描述符但栈和寄存器是独立的上下文切换开销上线程切换比进程切换快因为不需要切换地址空间也就省了TLB刷新。如果能顺带提一句“多线程模型中的1:1、N:1、N:M对比”那这题的得分层次就完全不一样。**另一个是内存管理。**虚拟内存几乎是必考而且角度很多。有的题问“为什么需要虚拟内存”有的题给一段代码问“这个地址是多少”还有的题考“malloc分配的内存什么时候真正占用物理内存”这个问题我特别想强调malloc返回的指针是虚拟地址物理页是缺页异常发生时才分配的。这是理解Linux内存的基础但很多人说不出“缺页异常”这四个字。如果你能把这个机制解释清楚再补一句“所以申请大内存不一定立刻占用物理内存但一旦逐个写入内存占用就开始体现”不管是笔试还是面试官都会对你另眼相看。**还有一个是并发同步。**B卷大概率会出现一段多线程代码让你判断输出。比如经典的i竞态两个线程对同一个int执行一万次自增最终结果一定小于等于两万吗答案是“小于等于两万”——因为i不是原子操作读、改、写三步可能交叉。考察点是想看你能不能识别出数据竞争以及能不能用atomic、mutex或线程局部存储来修复它。补充一个细节题目如果用的是C std::atomic 而不是int结果就是确定的两万但如果是volatile int依然不确定。这就是我在2.1说的volatile误会高频联动考点。Linux这块笔试一般不会让你现场操作但会以“命令输出”“文件描述符”“进程状态”等形式出现。比如“如何查看进程的内存占用”“ps命令显示什么状态”“select、poll、epoll区别”。epoll的出现频率特别高因为它是服务端高并发的基础。答这道题要避开一个误区不要只说“epoll是事件驱动”要具体讲出来select每次调用要把fd集合拷贝到内核并线性扫描epoll通过红黑树维护监视的fd用就绪链表记录触发的fd且通过mmap把内核事件表映射到用户空间减少了拷贝。这个题的答题深度直接决定了操作系统模块的分数上限。3. 数据结构、算法与网络拉开分差的得分区3.1 数据结构与算法题边界条件比思路更值钱系统软件开发岗的算法题难度通常不会太夸张但有一个特点非常看重边界条件处理和工程化表达。很多题目看似是“标准数据结构题的变体”但落笔之后才发现处处是坑。举个例子题目如果让你“实现一个LRU Cache”要求get和put都是O(1)。思路大家都背得下来哈希表加双向链表。但笔试阅卷尤其是人工阅卷会看更多你有没有处理capacity为0的情况get不存在的key返回什么put一个已存在的key时是先删旧节点再插入尾部还是直接改值并移动到尾部这些细节决定了一次性通过率。更重要的是你在类设计上有没有区分“缓存项”和“LRU索引”会不会把数据和链表节点耦合在一起——这是工程思维问题。再比如说“设计一个线程安全的单例”这题是C笔试的高频题。很多人直接写“加锁懒汉”然后被问“每次getInstance都加锁不浪费吗”而愣住。更好答案的思路是局部静态变量初始化即Magic Static。C11规定局部静态变量的初始化是线程安全的编译器会生成guard代码所以代码极简static Singleton getInstance() { static Singleton instance; return instance; }。如果能再解释一句“但要注意C11之前的编译器不保证这点所以也存在用call_once实现的版本”这道题就答满了。算法题的部分我的建议是针对性刷题不必贪多。系统软件岗的算法题有明显偏好链表、二叉树、哈希、字符串处理出现的概率远大于动态规划和图论。优先刷这几类并且每一题都要求自己手动构造边界测试用例。LeetCode的Hard难题可以战略性放弃——B卷里出现Hard的概率极低为了它占用大量时间不值得。还有一个老生常谈但经常被忽视的细节笔试编程题不是只给你一个IDE环境让你慢慢调。很多系统的输入输出是白板模式即代码放在一个大输入框里你需要自己从标准输入读取并打印结果。这种模式下输入解析代码的正确性是第一生产力。我见过太多算法思路全对、结果因为少读一个换行符而全盘皆输的案例。备考期间建议用各大在线笔试平台练题时故意不依赖自动填充和语法高亮每天做一两道题练手感和输出格式。3.2 网络基础答对容易答全难系统软件开发岗笔试在网络部分不会太深但“答对”和“答全”是两码事。以TCP握手为例。三次握手的次数很多同学能答对但简答题如果只写“客户端发SYN服务器回SYNACK客户端回ACK”最多拿一半分。至少还需要补充为什么要用三次而不是两次——因为两次无法避免“失效的连接请求突然到达服务器”造成的资源浪费这是经典的解释三次握手过程中两端各自完成了什么状态转变CLOSED、SYN_SENT、SYN_RCVD、ESTABLISHED第三次握手报文可以携带数据吗——理论上可以但一般不携带实际应用数据。同样的四次挥手时要答出TIME_WAIT状态的作用让延迟的报文段在网络中自然消失而不是影响新连接。TIME_WAIT持续多长时间2MSL为什么是2MSL因为最多等一个报文段来回的时长。UDP和TCP的区别不用说但要注意另一类高频概念题阻塞IO与非阻塞IO、同步与异步、IO多路复用。这种题表面是网络实际上是操作系统和网络协议的交叉。题目让你解释Reactor模式最少要提到事件循环、事件分发器、事件处理器三个角色select/poll/epoll是哪种层面的复用Reactor和Proactor的区别。能把“同步”和“阻塞”拆开——同步不等于阻塞异步不等于非阻塞——这就是加分项。HTTP部分一个高频考点是“浏览器输入URL到显示页面的完整过程”。这道题看着像综合题其实是网络、操作系统、编译的混合考察。一个完整回答至少包含DNS解析本地缓存、递归查询、TCP连接三次握手、HTTP请求发送、服务器处理并返回、浏览器解析渲染、TCP挥手。系统软件岗的要求比普通后端更高一层还需要提一下“静态资源可能走CDN”“HTTP/1.1的Keep-Alive和HTTP/2的多路复用”等优化点这让答案显得更加工程化。4. 从笔试到Offer可复用的备考路径与实操方法4.1 四阶段备考法从复习到模拟的完整路线先说明一下这套方法不是背答案而是把基础补牢、让知识形成网络。适合备考时间在4到8周的同学零基础和有一定基础都可以根据阶段调整时长。第一阶段第1周摸底与扫盲。找一份真实的系统软件开发岗笔试题不用限定是哪一年哪家完整做一遍模拟考试环境。这一步的核心是定位薄弱点是C的坑不熟还是操作系统概念模糊或者算法题无从下手。建议用一个表格记录每道题的状态对/错/蒙对按模块汇总。第二阶段第2到3周系统过基础。C就按《C Primer》加《Effective C》的章节来每天一个主题重点读析构函数、拷贝控制、内存模型、并发atomic、mutex、condition_variable这些章节。操作系统推荐《深入理解计算机系统》第8到12章或者《操作系统导论》。不要追求每一步都看懂但要保证“大概知道这个知识点在哪个大框架下”这样后续复习才有索引。第三阶段第4到5周专项刷题与核对。算法题按链表、二叉树、字符串、哈希、动态规划分类刷每天3到5题题目输出要整理成一篇“错题总结”。语言基础和操作系统就做各大厂的历年笔试题注意直接搜索“XX秋招 系统软件开发 笔试题”来积累不需要全部做完每年挑两三份足矣。重点是把做错的题的知识点写进笔记里形成“题目-考点-原理-变式”四元组后面密集复习时非常高效。第四阶段第6到8周全真模拟与查漏。每周做1到2次完整模拟笔试使用牛客网、赛码网等在线平台从严计时。模拟的目的不是刷题量而是训练时间分配和心理节奏。考试时如果卡在简答题超过十五分钟该跳过就跳过编程题如果十分钟内没有AC思路果断先做下一道。这些决策习惯练出来的价值不比多刷十道题低。4.2 笔试现场的节奏控制与答题策略备考内容再夯实现场节奏崩了也白搭。分享几个我实际用过的答题策略。第一先花两分钟通读全部题目。这个很重要。B卷里可能出现一道你熟悉的题目也可能出现一道完全陌生的题目。通读一遍后先把最有把握的选择题和填空题做掉保证基础分拿到手。系统软件开发笔试的选择题通常分值不低且没有负分蒙对一个是一个。第二简答题用“总分结构”作答。先给结论再展开解释最后补充细节。比如“memset和for循环赋值有什么区别”先写结论“memset是按字节填充for循环是按元素类型赋值”再展开讲“所以对int数组赋0以外整数时memset结果是错误的而for循环可以赋任意值”。阅卷一般是按采分点给分把结论和关键原理写在第一句没时间深入时也不亏。第三编程题先写结构后填实现。哪怕是白板代码也先在注释里写清楚数据结构定义、主函数流程、边界处理。这既是为了让阅卷老师看懂思路也是给自己理清逻辑。比如实现LRU时第一行注释写“双向链表节点保存key、value、prev、next哈希表保存key到节点指针的映射”后面实现就不会乱。有些笔试系统即使代码不能完全跑通也会根据思路给步骤分。还有一点编程题注意看题目对函数签名和输入输出的要求。有的系统要求你自己实现main函数并读标准输入有的系统只要求补全一个函数。这两种形式的备考手感完全不同。多去真实平台参加模拟笔试非常有必要千万别只在本地IDE上舒服地写题那是一种“温室训练”。5. 那些真题之外的坑我的踩坑记录与提醒5.1 五个最容易翻车的典型问题每年笔试我都能在论坛上看到大量“为什么我准备充分还是挂了”的吐槽。这里总结五个最典型的翻车原因全部来自真实反馈和我自己面试别人的观察。第一个知识点背得溜但不会变通。比如知道“引用不能为空”但题目换成“以下哪个写法会在运行时崩溃”时就没反应过来一个返回引用的函数如果返回了局部变量临时对象的引用实际上也悬空。这类问题的根源在于学习时只记忆“结论”而没有理解“为什么”——结论只是表面机制的深层理解才是应对变式的基础。第二个算法题能AC但代码风格一塌糊涂。系统软件开发岗的阅卷人往往更在意代码风格。变量名用a、b、c写完不释放内存没有处理空指针这些问题在LeetCode的“只判断结果”环境中丢不了分但在人工阅卷中被扣得很多。倒不是阅卷人故意苛刻——风格直接反映你是否具备生产级代码的素养——而是系统软件开发这个岗位本身就是写生产级C/Java代码的人风格是基本盘。第三个只答结论不给依据。比如Linux进程调度很多人写“完全公平调度CFS”然后就没了。但实际笔试阅卷时踩分点在于“CFS通过虚拟运行时间实现公平性、选择虚拟运行时间最小的进程运行、nice值影响权重计算”这些细节。单写一个名词跟没写几乎一样。第四个在编程题上死磕到底。一道题没AC不甘心花二十分钟debug结果后面简单的简答题没时间写。这个错误几乎是每年笔试的重灾区。我自己的原则是编程题15分钟没有进展就暂时放下先做后面的题。等全部做完有余力再回头补。时间管理是笔试的一部分也是考察的一部分。第五个笔试环境不熟悉。很多平台要求使用特定浏览器、禁止复制粘贴或者只允许使用某种输入法切换。每年都有人因为在线编辑器里找不到“运行”按钮、或者是代码缩进被自动替换导致编译错误而白白丢分。考前务必上牛客或赛码网跑一次完整模拟把环境、字体、快捷键都摸清楚。5.2 给不同基础同学的自查清单最后按不同基础给一份自查清单。你能在笔试前一周完成大部分“是”这一趟就不会白去。如果你现在还处于“学过C但没写过完整项目”的状态能不能写出空类、含虚函数的类、继承体系的sizeof推导过程并说明理由能不能解释malloc和new的区别以及各自在内存分配失败时的行为能不能画出TCP三次握手和四次挥手的完整状态机能不能手写一个线程安全的单例并说明每个关键字的用途能不能说明一个进程从启动到main执行中间经历了什么如果你已经有了一定工程经验或者做过系统相关的项目有没有完整分析过线上程序的栈溢出或内存泄漏能不能说清楚自己项目的线程模型为什么选这个而不是别的方案遇到性能问题时能不能用perf、strace等工具定位到具体的函数和系统调用能不能解释自己用过的网络库的事件分发机制比如epoll的LT和ET模式区别写出一个真实场景中并发bug的复现过程和修复方案这些自查项不是为了吓唬人而是想让你看清系统软件开发笔试题只是一个入口真正决定笔试分数的是你平时积累的系统认识。基础知识可以靠短期冲刺但系统思维和工程直觉需要更长时间的沉淀。回到“小米2019秋招系统软件开发笔试题B”这个话题上来我的最终建议是去找往年真题来练手感但不要以“背下来”为目标而是以“我能不能比答案解释得更深”为目标。如果你看到一道题能说出命题人想考察哪个知识点、这个知识点在实际系统里是怎么体现的那你离这份Offer的距离就只在面试那一步了。
返回列表