ARTICLE DETAIL

资讯详情

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

C++校招笔试高频考点复盘:从迅雷B卷看语言、算法与并发

C++校招笔试高频考点复盘:从迅雷B卷看语言、算法与并发 如果你经历过 2018 年前后的互联网校招看到迅雷校园招聘C在线笔试B卷这个标题应该会条件反射地想起那种在牛客网或赛码网上掐着时间答题的紧张感。那年的B卷不是随便出的一套题它代表了一类相当典型的互联网公司技术岗笔试——选择题抠C语法细节简答题考多线程和设计思想编程题考算法基本功三个环节只要有一个拖后腿基本就告别面试了。以这套B卷为样本去拆考点我觉得比刷十套模拟题都更有针对性。这篇文章就围绕这套B卷涉及的核心技术点展开C语言底层、算法高频套路、并发与设计模式、以及在线笔试环境下的备考策略。不管你是正在准备校招的应届生还是想补C基础的转行者都可以按这个思路去复盘自己的复习体系。1. 先把B卷的战场地图画出来题量、难度与筛选逻辑1.1 那年B卷的典型构成2018年迅雷校招C岗位的笔试在线作答题型大体是单项选择、填空题、简答题、编程题。选择题一般十道出头覆盖const、引用、指针、虚函数、内存对齐、STL使用细节填空题偶尔会出现让补充代码片段或判断程序输出简答题围绕多线程、设计模式、内存管理出题编程题两到三道常见的有字符串处理、链表操作、数据结构模拟和基础算法题。这套结构放到现在看也并不过时。它的特点是语言题量占比高且往往放在最前面目的是快速筛掉基本功不扎实的人。很多候选人死在第一道选择题上不是因为不会而是因为在线笔试环境紧张读题太快把哪个说法错误看成哪个说法正确。这类低级失误在B卷里尤其致命。1.2 B卷和A卷的差异为什么同一批笔试要分卷同一场笔试分A、B卷是当时很多公司防作弊的常规操作。A、B卷在整体难度上大体一致但题目顺序、选择题选项打乱部分题目会替换成同等难度的新题。有些公司甚至根据投递时间或岗位方向分配不同卷子比如C岗和Java岗共用一套逻辑题但语言专项部分完全分开。B卷相比A卷通常会在语言细节上更刁一点。这不是说B卷更难而是它更愿意考那些看起来简单但容易记错的点比如constexpr是哪一版C引入的、字符串数组初始化在不同写法下的差异、C标准库某个函数的时间复杂度。这类题不像编程题那样有区分度但用来做第一轮淘汰非常高效。1.3 从热搜词里能读出考什么大家搜得最多的地方就是失分点如果去翻当年大家搜得最多的C相关问题会发现一个很有意思的现象高频搜索词几乎就是笔试失分点的集合。热搜词对应考点常见失分原因constexpr 哪个C版本引入的C11新特性把版本记混c字符串数组初始化字符数组与指针、string分不清数组与指针的sizeof、是否含\0aba问题cCAS并发只背概念不理解场景快速幂算法c数值算法边界与防溢出没处理好单调栈算法c数据结构不会维护单调性vscode配置c/c环境构建工具链本地编译不过笔试心态崩这张表基本对应了B卷的考核重点语言标准、内存、并发、算法、工程环境。备考时盯着这些点去补不会跑偏。2. 语言底层题const/constexpr、字符串初始化与内存布局2.1 constexpr 是 C11 引入的版本题为什么值得单独记如果B卷出一道选择题问constexpr 是哪个C版本引入的答案是C11。这题本身不难但它被搜上热搜说明好多人确实记混了。C11引入了constexpr允许声明编译期可求值的变量和函数C14放宽了constexpr函数体内的语句限制允许局部变量和循环C17进一步支持了if constexpr和lambda表达式中的constexprC20又加了consteval和constinit。笔试考这个点不是单纯考版本号而是想确认你是否理解编译期求值和运行期变量的区别。常搭配的进阶问法是constexpr函数是否一定在编译期执行答案是否定的如果实参不是常量表达式编译器会退化成普通函数调用。这一类是不是一定的陷阱在选择题里出现频率很高。2.2 字符串数组初始化的三种写法char数组、指针、string 的边界差异字符串数组初始化是所有C笔试几乎必考的题。直接看代码char str1[] hello; // 字符数组大小6含\0内容可修改 const char* str2 hello; // 指针指向字符串字面量存储在只读区不可修改 std::string str3 hello; // 标准库类型动态管理内存功能最全常见的坑有三个。第一个sizeof(str1)是6strlen(str1)是5很多人在线笔试时把这两个结果搞混导致后面字符串处理题全错。第二个char* str hello在C11之后是非法写法因为字符串字面量的类型是const char[]不能隐式转换为char*有些老编译器只给警告但B卷的编译器往往开了-Werror直接编译失败。第三个str2指向只读区尝试修改str2[0]是未定义行为程序可能直接崩溃。B卷如果要加大难度会把问题包装成以下哪个选项的输出结果正确并混入strcpy、memcpy等调用考察你是否清楚源字符串和目标缓冲区各自的容量。这种题没有太多技巧平时把数组、指针、string三种存储模型对比着写一遍考场上就不会慌。2.3 结构体链表与内存对齐指针题背后的底层逻辑c结构体链表基本语法能进热搜说明不少人连最基础的数据结构定义都要现搜。链表节点的标准写法struct Node { int data; Node* next; Node(int x) : data(x), next(nullptr) {} };B卷如果考链表重点往往不是定义而是操作链表的细节头插法、尾插法、反转链表、删除节点。最容易扣分的是指针操作顺序比如反转链表时忘记保存下一个节点导致断链。这类题要练到条件反射考场上没有时间现场推导。和链表同时出现的还有内存对齐问题。比如struct Test { char a; int b; };sizeof(Test)在多数64位平台上是8不是5。因为成员b要按4字节对齐a后面补了3个字节。理解对齐规则不仅是为了做对选择题也是排查程序内存异常和性能问题的基础。2.4 读入整行与字符串转数组在线笔试的隐藏杀手C 读入整行被反复搜索是因为在线笔试的输入处理比很多人想象得更暗坑。经典问题场景int n; std::cin n; std::string line; std::getline(std::cin, line); // 这里读到的可能是空行原因在于getline会读取上一次cin 留下的换行符。解决办法是先调用std::cin.ignore()清掉缓冲区里的换行符或者统一用getline读取所有内容再逐行解析。字符串转数组也是高频操作。C里没有Python那种split常用的做法是std::vectorstd::string parts; std::string item; std::stringstream ss(input); while (std::getline(ss, item, ,)) { parts.push_back(item); }如果用VSCode配C/C环境自己练题这种输入问题本地能复现但考场上用的是平台自带编辑器出了问题只能靠经验快速判断。建议考前把cin、getline、istringstream的搭配使用写成自己的模板代码直接复制粘贴节省时间。3. 算法题高频套路快速幂、最小公倍数、单调栈与排序边界3.1 快速幂从二进制拆解到取模防溢出快速幂在B卷里出现的概率非常高因为它考察了三个基础能力位运算、分治思想、溢出防范。核心思路是把指数b按二进制拆解比如计算2^1313的二进制是1101即2^13 2^8 * 2^4 * 2^1。每次循环把底数平方当当前位为1时就乘入结果。long long fastPow(long long a, long long b, long long mod) { long long res 1 % mod; a % mod; while (b 0) { if (b 1) { res res * a % mod; } a a * a % mod; b 1; } return res; }两个细节值得注意。第一res的初始值写成1 % mod是为了兼容mod等于1时结果为0的边界情况。第二a a * a % mod这一步如果a接近1e9相乘会超出int范围必须用long long。如果题目数值继续加大到1e18级别long long相乘也会溢出这时要用快速乘或者__int128处理。3.2 n个数最小公倍数先除后乘别让溢出毁了ACn个整数的最小公倍数怎么求C这个热搜词对应的其实是一道看起来很简单、但很容易写错的题。两个数的最大公约数用欧几里得算法long long gcd(long long a, long long b) { return b 0 ? a : gcd(b, a % b); }求最小公倍数的公式是long long lcm(long long a, long long b) { return a / gcd(a, b) * b; }关键在于先除后乘。a和b的乘积可能达到1e18甚至更大先做除法能有效避免中间结果溢出。n个数的最小公倍数按顺序两两迭代即可long long ans 1; for (int i 0; i n; i) { ans ans / gcd(ans, nums[i]) * nums[i]; }这道题在B卷里可能以填空题或编程题的一个子步骤出现。不要因为简单就大意溢出的坑往往就埋在这种送分题里。3.3 单调栈、树遍历与消息传递/物流网络类模拟题热搜词里出现了NOIP2013模拟联考15 消息传递(news) c和GESP 202603 七级 物流网络这两类题在B卷里属于模拟图论的结合体。很多人一看到题目描述很长就发懵其实拆解下来就是给定一棵树或一张图按某种规则传播消息或运输货物求传播时间或路径。消息传递类题目如果是在树上通常用DFS或BFS解决步数代表传播轮数。如果是分层传播要维护队列和访问标记避免重复入队。物流网络类题目则可能涉及最短路径或最小生成树数据规模小可以用Floyd规模大就要换Dijkstra或SPFA。单调栈是另一种B卷高频套路典型场景是下一个更大元素和直方图最大矩形。核心思想是维护一个栈内元素单调递增或递减的栈新元素入栈时弹出破坏单调性的元素。以下一个更大元素为例vectorint nextGreater(vectorint nums) { int n nums.size(); vectorint res(n, -1); stackint st; for (int i 0; i n; i) { while (!st.empty() nums[i] nums[st.top()]) { res[st.top()] nums[i]; st.pop(); } st.push(i); } return res; }这个算法的关键在于栈内存的是下标而非值因为我们要根据下标去填结果数组。B卷如果考单调栈编程题的最后一步往往就是让你输出每个位置的下一个更大元素理解了下标入栈这个细节整道题就通了。3.4 冒泡与选择排序基本功里的稳定性和边界别小看冒泡排序和选择排序B卷的语言细节题经常拿它们做文章。比如问以下哪个排序算法是稳定的答案包含冒泡不包含选择。因为选择排序每次把最小值放到前面可能把等值元素的相对顺序打乱。另一个常考点是冒泡排序的优化。经典写法void bubbleSort(vectorint arr) { int n arr.size(); bool swapped true; for (int i 0; i n - 1 swapped; i) { swapped false; for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { swap(arr[j], arr[j 1]); swapped true; } } } }加了swapped标记后如果某一轮完全没有交换说明数组已经有序可以提前结束。这在笔试中可能体现为最好情况时间复杂度O(n)。选择排序无论什么情况都要比较n*(n-1)/2次时间复杂度固定O(n^2)但交换次数最多n-1次。这些结论如果没理解只靠背遇到换一种问法就会懵。4. 多线程、回调与设计模式B卷里体现工程能力的小题4.1 ABA问题从CAS到版本号C ABA问题能登上热搜说明很多人是在被问到之后才去查的。ABA问题发生在CASCompare-And-Swap操作中线程1读取内存值为A线程2把值从A改为B又改回A然后线程1执行CAS时发现内存还是A比较成功但实际的中间状态已经被修改过。在C里std::atomic提供的compare_exchange_weak和compare_exchange_strong都可能遇到ABA问题。最简单的解决思路是引入版本号或标记位每次修改不仅更新值还更新版本号CAS时同时比较值和版本号。很多无锁数据结构通过这个方式规避ABA问题。B卷面对这个考点一般不会要求你写出完整的无锁数据结构而是用简答题考察你是否理解CAS本身的问题。答题时先描述ABA场景再说明危害最后给出版本号方案基本就能拿全分。4.2 回调函数从函数指针、std::function 到 lambdac回调函数例子这个热搜词反映的是笔试中一道经典简答题什么是回调函数C中如何实现。回调用最简单的说法是把一段可执行代码作为参数传给另一个函数在特定时机被调用。C语言时代用函数指针void eventHandler(int code) { std::cout code: code std::endl; } void setHandler(void (*handler)(int)) { handler(42); }C11以后更推荐std::function和lambda#include functional std::functionvoid(int) handler [](int code) { std::cout code: code std::endl; }; void setHandler(const std::functionvoid(int) cb) { cb(42); }lambda相比函数指针的优势是能捕获上下文变量。笔试如果让你分析一段代码的输出要注意lambda的捕获方式按值捕获[]在lambda创建时就复制了变量按引用捕获[]则使用外部变量的实时值。这个点经常被拿来考一旦混淆输出结果完全对不上。4.3 设计模式单例、工厂、观察者的笔试问法设计模式在B卷里一般以简答题出现。单例模式几乎是必背的C11之后最简洁的线程安全写法是class Singleton { public: static Singleton getInstance() { static Singleton instance; return instance; } Singleton(const Singleton) delete; Singleton operator(const Singleton) delete; private: Singleton() {} };局部静态变量在C11标准下初始化是线程安全的编译器会生成防护代码确保只初始化一次。笔试时经常让分析这种写法为什么线程安全或还能怎么写把双重检查锁的写法也准备一下会更稳。工厂模式的考题重点是工厂方法解决了什么问题——让客户端通过工厂创建对象避免在代码里直接new具体类从而解耦。观察者模式则常和回调函数结合考察发布-订阅的思想。答题时不求代码完整把意图和关键接口说清楚就很能体现工程意识。4.4 构建环境与运行库VSCode配置和VC Redistributable 为什么会被搜爆看到vscode配置c/c环境和visual c redistributable这样的热搜词你可能觉得和笔试题无关实际上它们决定了笔试前的复习效率。VSCode配置C/C开发环境需要三个核心文件tasks.json负责编译任务launch.json负责调试c_cpp_properties.json负责IntelliSense的编译器路径和头文件路径。配置不正确语法提示消失、编译报错练习效率会直线下降。VC Redistributable是运行很多Windows下C程序的运行时依赖缺了它会出现找不到VCRUNTIME140.dll之类的错误。这不是笔试考点但如果自己的练习环境都跑不起来考场上更不可能写好代码。我的建议是考前至少留三天用和在线笔试平台接近的编译器版本比如GCC 4.8到GCC 7看平台说明练习避免在考场上遇到本地能编、线上编译失败的情况。5. 从B卷复盘出的备考策略时间分配、输入边界与临场节奏5.1 在线笔试的时间分配先保编程题再抠选择题以B卷常见的90到120分钟时长计算合理的时间分配策略是拿到卷子先快速浏览一遍所有题目大致标记出编程题的难度然后用前三分之一的时间快速解决选择题和填空题剩下的时间优先做编程题最后用富余时间回头检查不确定的题。很多应届生容易犯的错误是在选择题里死磕为了一道关于内存对齐的题花掉15分钟导致后面编程题没时间写。编程题在评分中的比重通常超过50%一道AC的题目比三道选择题都值钱。先把能拿的大分拿到手再去抠细节。5.2 把题目翻译成算法拆解模拟题的步骤消息传递、物流网络这类长题干的题目核心能力是翻译。我一般按三步走把题目的业务场景转化为数据结构。消息传递通常是一棵树或一张图物流网络也是图。确定计算目标。是求最短路径、最少轮次还是某种最大值/最小值。根据数据规模选择算法。n在1000以内可以考虑O(n²)的Floydn在1e5级别必须用O(nlogn)的Dijkstra或O(n)的BFS。这三步在脑子里过完再开始写代码。数据规模是选择算法的最重要依据B卷的题目一般会给出明确的范围不要忽略。5.3 2018年那批校招的真实节奏提前批、正式批与B卷的意义2018年校招的时间节奏大约是7到8月提前批内推9月正式批大规模笔试面试。B卷往往出现在正式批中由于投递人数太多HR会分批安排笔试B卷就是其中一批。这意味着题目难度不会太极端因为最终还是要按比例选出进入面试的人。还有个容易被忽略的点很多公司允许笔试后手动提交代码或截图平台挂掉的情况也时有发生。遇到这类问题先截屏保留证据再联系HR说明一般都会安排重考。不要因为一次平台故障影响心态。5.4 易错点自查表考点常见错误对策constexpr 版本记成C17记牢C11顺带理清14/17/20演进字符串数组sizeof和strlen混用理解\0、存储区、可修改性最小公倍数a*b先运算导致溢出先除后乘getline读入读到残留换行符cin.ignore()快速幂取模忘记底数先取模每次运算都modCAS ABA只答加版本号不解释先说场景再给方案排序稳定性选择排序被误判为稳定对比交换过程我在实际带人的过程中发现笔试备考最有效的动作不是刷十套题而是把每个高频考点的代码模板敲熟。B卷考的是你的条件反射看到字符串转数组马上想到istringstream看到最小值、最大值、下一个更大元素马上想到单调栈或堆看到取模运算马上检查底数和中间结果。这种反射能力只能靠重复练习培养出来没有捷径。最后分享一个自己的习惯准备一个专门的笔试模板文件夹里面放好快读、快速幂、gcd/lcm、单调栈、并查集、Dijkstra等常见算法模板考前几天反复默写。虽然在线笔试系统不让你翻本地文件但默写过的代码会形成肌肉记忆实际敲起来速度快很多。希望这篇复盘能帮你在下一场笔试里少踩几个坑。
返回列表