C++校招笔试备战指南:从核心知识点到算法模板的全面拆解
聊一个每年都会被反复问起的话题:C++开发岗的校招笔试到底怎么准备。尤其是网易这种大厂的正式批,题量和难度都不是随便刷几十道LeetCode就能应付的,它既要考察你对C++语言本身的掌握深度,又要看你在有限时间里的工程思维和代码实现能力。这篇东西我结合近两年校招笔试的常见风格,以网易2023校招笔试C++开发工程师(正式第二批)为切入点,把笔试前中后最值得关注的东西拆开讲一遍,包括考点分布、高频知识点、算法套路、环境配置和复盘方法,希望能给准备C++校招的同学一条相对清晰的路线。
这篇文章适合谁看?一种是已经投了简历、正在刷题准备笔试的应届生,另一种是刚学完C++基础、想了解大厂笔试到底考什么的学生。不管你属于哪一类,按我这个思路去准备,至少不会在笔试现场发懵。
1. 笔试之前:先把岗位和考察方向摸清楚
1.1 网易C++开发岗位到底在招什么样的人
网易的C++开发岗位并不是一个笼统的“后台开发”,它覆盖的方向很多:游戏引擎、客户端、服务端、云音乐底层、云信通信、大数据中间件等。不同方向对C++的侧重点差别很大,但笔试阶段基本是一套通用C++卷子,这意味着你不需要猜测具体是哪个组出的题,只需要把C++语言和数据结构算法这两个基本面打扎实。
从笔试的角度看,网易这类大厂考察的核心其实是三件事:第一,你是否真正理解C++的对象模型、内存管理、模板和STL的实现机制,而不是只停留在“会用”的层面;第二,你是否具备扎实的算法功底,能在限时内把一道中等偏难度的题写出来并保证正确性;第三,代码风格和边界处理能力,很多同学思路是对的,但一写代码就漏边界条件,这类人往往会被卡在笔试筛选中。
我自己带过不少实习生,也看过很多校招简历,一个很直观的感受是:C++岗位的笔试筛选,筛掉的往往不是不会写算法的人,而是“以为自己会C++、但实际上说不出底层原理”的人。所以准备笔试前,建议先给自己做个摸底,问几个问题:虚函数表是怎么分布的?vector扩容的拷贝/移动语义是怎么触发的?std::function和函数指针的区别是什么?如果答不上来,那就说明你的C++复习还停留在语法层面,笔试选择题会很吃亏。
1.2 校招笔试的常见流程与平台细节
网易校招笔试通常采用牛客网或赛码网这类在线评测平台,笔试时间一般安排在工作日晚上的19:00到21:00左右,持续120分钟。题型分布大致是:单选题15~20道、多选题5~10道、编程题2~3道,部分批次还可能包含简答题或设计题。
这里有一个容易被忽略的点:在线OJ环境和本地IDE是有差异的。你本机用VS Code写得好好的代码,粘贴到OJ上可能因为头文件缺失、输入输出格式不对而编译失败。所以笔试前一定要去牛客网熟悉一下它的代码编辑器,尤其是“本地通过、提交不过”这个问题——绝大多数都是因为main函数返回值、输入循环读入方式、或者输出多了空格换行这些细节。
提示:网易笔试的编程题通常允许使用C++14或C++17标准,支持STL,但不同批次的编译器版本可能不同。考试前记得看考试须知,如果支持C++17就直接用结构化绑定、std::optional这些特性,如果不确定版本就老老实实写C++11兼容代码。
笔试开始前还有几个实操细节需要提前确认:身份证/学生证放在手边,网络稳定,准备一个本地调试环境以备在线编辑器不好用的情况。另外建议准备一个自己的代码模板,比如快读快写模板、常用头文件集合、并查集模板、最短路模板,这个在笔试前整理好,能帮你节省不少时间。
2. 试卷结构与高频考点拆解
2.1 选择题:C++基础、八股文和易错点
网易笔试的选择题部分覆盖面很广,但C++相关题目主要集中在以下几个方向:虚函数和多态、const和constexpr、static关键字、智能指针、左值右值与移动语义、类型转换、内存对齐、STL容器底层实现和迭代器失效问题。
这些题目表面上考的是语法细节,但背后考的是语言机制。比如它问你“下面哪一个不会引起vector迭代器失效”,这时候你如果只靠背结论,换一个问法就容易懵。更好的复习方式是把每一个易错点都往“为什么”方向深挖一层:vector在插入元素导致重新分配时,所有迭代器都会失效;但如果只是erase掉中间某个元素,那被删元素之后的迭代器会失效,之前的不会。这个结论不是靠背,而是因为vector底层是连续内存上的动态数组,理解了内存模型,你就能推导出所有迭代器失效场景。
为什么这里强调“理解底层”而不是“背诵”?因为校招笔试题有一个特点:同样的知识点,它一定会换一个说法来考你,甚至会把两个知识点混在一起出题。比如“const char* p”和“char* const p”的区别、或者“在C++11以后,为什么建议用nullptr而不是NULL”,这些如果只是背结论,到了考场上换个包装照样错。
我做了一个高频选择题考点的整理,供大家对照自查:
| 知识点 | 常见考法 | 易错点 |
|---|---|---|
| 虚函数与多态 | 构造函数/析构函数能否为虚函数 | 构造函数不能是虚函数,析构函数建议声明为虚函数 |
| 内存对齐 | 结构体sizeof计算 | 对齐规则、pragma pack的影响 |
| 左值右值 | std::move和移动构造的使用场景 | move之后原对象处于“有效但未指定”状态 |
| 智能指针 | shared_ptr循环引用能否导致内存泄漏 | 循环引用必须用weak_ptr打破 |
| 类型转换 | static_cast/dynamic_cast/const_cast/reinterpret_cast的区别 | dynamic_cast要求多态类型且运行时安全检查 |
| STL容器 | map底层红黑树,unordered_map底层哈希表 | 有序性和复杂度差异 |
| 动态内存 | new/delete与malloc/free的差异 | new会调用构造函数,delete会调用析构函数 |
2.2 编程题:算法、STL与工程落地
网易笔试的编程题一般2~3道,通常是一道简单/中等题、一道中等偏难题、一道综合题。简单那题往往就是字符串处理或模拟,中等题可能是动态规划、贪心、二分、图论中的一种,综合题则可能把多个知识点串在一起,比如“字符串+哈希+双指针”的组合。
你需要特别注意的一点是:笔试编程题只要求你提交一个可以运行的完整程序,并不要求你封装成一个类。这和LeetCode上的做题方式有明显的差异——LeetCode已经帮你把输入输出处理好了,你只需要写核心函数,但校招笔试通常要求你自己处理输入,如果输入读取方式不对,即使算法正确也会挂。
举例来说,假设题目要求读取多行,每行两个整数,遇到EOF结束,正确写法是:
#include <bits/stdc++.h> using namespace std; int main() { int a, b; while (cin >> a >> b) { cout << a + b << endl; } return 0; }看起来简单,但如果你写成固定读一次或没有处理EOF,在线评测就会判你超时或答案错误。
此外,笔试编程题对复杂度的要求往往会在描述中明确给出,比如“n <= 10^5”时,你的算法必须达到O(n log n)或O(n),如果是O(n^2)基本就超时。所以笔试前一定要养成先看数据范围的习惯,数据范围直接决定了算法选型,这比上来就写代码重要得多。
2.3 笔试题的难度与时间分配建议
以正式第二批的难度来估算,选择题的阅读量其实不小,很多同学会陷在某个多选题里反复纠结,最后编程题时间不够。我的建议是:选择题每道控制在1.5分钟以内,遇到拿不准的先标记跳过,不要浪费超过2分钟,编程题按“先易后难”的顺序做。
先把有把握的编程题做出来、提交并且通过自测,再回头啃不会的选择题。这里的逻辑是:编程题在总分中的占比通常更高,而且两题之间的分值差距可能很大,首先把能拿的分数拿到手,这是笔试时间管理最重要的原则。
时间分配参考表:
| 题型 | 建议用时 | 策略 |
|---|---|---|
| 单选/多选题 | 40~50分钟 | 不会的先跳过,不要恋战 |
| 编程题第1题 | 20分钟 | 通过全部用例再提交 |
| 编程题第2题 | 30分钟 | 先暴力再优化,拿部分分 |
| 编程题第3题 | 20~30分钟 | 写不出正解也要写暴力/特判 |
| 检查 | 10分钟 | 检查编译环境、输入输出格式 |
有一种很典型的丢分场景:编程题写完了但没测试极端边界,比如数组长度为0、输入负数、字符串为空的情况。笔试结束考官不会给你任何反馈,所以提交前务必自己构造几个边界用例去跑一遍。
3. C++核心知识点系统复习
3.1 constexpr的作用与版本演化
热词里有一个“constexpr哪个C++版本引入的”,这个问题本身也是笔试选择题的高频考点。constexpr是在C++11中引入的关键字,它的核心价值是让表达式在编译期就能被求值,从而把一部分运行期计算转移到编译期,提升程序运行效率。
C++11刚引入constexpr时限制很多:函数体只能有一条return语句,循环、分支都不能用。C++14大幅放宽了限制,允许在constexpr函数中使用局部变量、循环和分支。C++17之后,constexpr变得更加强大,甚至可以在构造函数中使用,从而构造constexpr对象。到了C++20,constexpr函数中可以出现try-catch和某些形式的动态内存分配,但校招笔试问到这一层的不多,记住C++11引入、C++14放宽、C++17支持constexpr构造函数这几个里程碑就够用了。
举个例子,笔试中可能会出现这样的题目:判断以下代码能否编译通过。
constexpr int square(int x) { return x * x; } constexpr int val = square(5);C++11和C++14都能编译,因为函数体只有一条return语句。但如果把square改成多行循环写法:
constexpr int sum(int n) { int s = 0; for (int i = 1; i <= n; ++i) { s += i; } return s; }这段代码在C++11标准下编译不过,在C++14标准下可以。这就是常考的点。答案是:C++14在编译期求值能力上做了大升级。做题时如果题目没有明确说明标准版本,笔试环境通常默认支持C++14或C++17,按较新标准理解即可。
3.2 多线程、ABA问题与并发安全
“ABA问题C++”是另一个非常典型的高频考点。ABA问题发生在无锁编程的CAS(Compare-And-Swap)操作中。简单来说,线程1从内存位置X读取到值A,然后被调度挂起;线程2把X从A改成B,又改回A;线程1恢复运行后执行CAS,发现X还是A,于是判断“没人动过”,CAS成功——但实际上这个位置已经被线程2修改过两次了。
为什么这是一个问题?因为CAS比较的只是“值是否相等”,它无法判断“这个值是不是被修改过后又变回了原样”。在需要基于状态流转做决策的场合,ABA问题会导致逻辑错误。比如一个用CAS实现的栈,如果栈顶节点被弹出又压入一个地址相同的节点,另一个线程可能误判栈没有变化。
解决办法最常用的是版本号/标记法,也就是在要保护的变量旁边加一个递增的版本号,每次修改都同时更新版本号,CAS时不仅比较值,还比较版本号:
struct Node { int data; }; std::atomic<int> version{0}; std::atomic<Node*> ptr{nullptr}; void update(Node* new_node) { Node* old = ptr.load(); int old_ver = version.load(); // 需要同时比较ptr和version // 在C++中可以用atomic<std::pair<...>>或指针标记打包实现 }笔试里一般不会让你完整实现一个无锁容器,更多是考概念:ABA是什么、为什么危险、常见解决方案是什么。应对策略是把“Compare-And-Swap、值相同不代表没变过、版本号方案”这三句话讲清楚。
在校招面试中,多线程的考察还会延伸到std::thread、std::mutex、std::atomic、条件变量、死锁的四个必要条件等。笔试选择题可能考到的点包括:unique_lock和lock_guard的区别,atomic为什么能保证原子性,内存序(memory_order)的含义。这些不需要你写出完整的并发代码,但概念要能辨析清楚。
3.3 设计模式与C++实现
“C++设计模式”搜索热度一直很高,网易笔试虽然很少直接考“请用代码实现单例模式”,但选择题中经常出现设计模式相关的判断,比如“下面哪种设计模式用于在不改变类的前提下扩展功能”选项里混着模板方法、策略、装饰器、适配器,这些容易混淆。
备考建议是至少把单例、工厂、观察者、策略、装饰器这五种的类图和应用场景吃透。单例模式必须能手写,包括两个版本:
// 懒汉式(线程安全版本,C++11之后) class Singleton { public: static Singleton& getInstance() { static Singleton instance; return instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() {} };C++11之后,局部静态变量的初始化是线程安全的,所以不需要自己加锁,这个写法既简洁又安全,笔试/面试中写这个版本基本不会错。
工厂模式在游戏开发中应用很广,网易游戏方向的岗位尤其喜欢考。简单工厂的本质是“用一个工厂类根据参数决定创建哪种产品”,工厂方法的本质是“把创建逻辑延迟到子类”,抽象工厂则是“创建一族相关产品”。选择题里常考的就是这几个概念的区分。
3.4 C++面试必背的“八股文”清单
“C++八股文”这个词在热词里出现频率很高,其实它指的就是那些校招面试中反复出现的基础题。准备笔试同样需要这些知识,因为选择题就是八股文的选择题版。我按自己的经验整理了一个最短清单:
| 八股文问题 | 必考点 |
|---|---|
| 虚函数是怎么实现的 | 虚表指针、虚函数表、动态绑定 |
| vector底层机制 | 动态数组、倍增扩容、迭代器失效 |
| 智能指针有哪些 | unique_ptr/shared_ptr/weak_ptr、引用计数 |
| 深拷贝浅拷贝 | 默认拷贝构造函数是浅拷贝、需要深拷贝时自实现 |
| new和malloc区别 | 构造/析构、类型安全、重载、失败处理 |
| 多态条件 | 继承、虚函数重写、基类指针/引用调用 |
| STL六大组件 | 容器、算法、迭代器、仿函数、适配器、配置器 |
| map和unordered_map区别 | 红黑树 vs 哈希表、有序性、复杂度 |
| 静态库和动态库区别 | 编译期链接 vs 运行期加载、体积与发布 |
| 回调函数 | 函数指针、std::function、std::bind、lambda |
这些不是背一遍就完事,每一条最好都能在十分钟内讲清楚。笔试的选择题往往就是从这些角度切入的,只是用选择和判断的方式考察罢了。
4. 编程题里让人上分的算法套路
4.1 快速幂:高频且短小精悍
热词里“快速幂算法C++”搜索量很高,这确实是一个笔试/面试都常考的算法,短小、经典、能考察位运算和分治思维。快速幂的核心是二分幂思想:把指数b拆解成二进制形式,从最低位开始处理,同时不断把底数平方。
long long fastPow(long long a, long long b, long long mod) { long long ans = 1 % mod; a %= mod; while (b > 0) { if (b & 1) { ans = ans * a % mod; } a = a * a % mod; b >>= 1; } return ans; }为什么这个算法是O(log b)?因为每循环一次,指数b的二进制位右移一位,循环次数等于b的二进制位数。笔试里如果题目要求计算a的b次方对p取模,且b的范围达到10^18,那么直接for循环乘法是绝对超时的,必须用快速幂。
这里有一个笔试很容易踩的坑:a和b的类型必须给足,如果a, b, mod都是int,a * a这一步就可能溢出。所以建议在实现时直接把参数定义成long long,模数传给函数后再取一次余,保证乘法不越界。
注意:笔试中所有可能进行乘法的中间变量,一律用long long。这是一个成本极低但收益极高的习惯,很多人的题本来思路完全正确,就是因为没用long long爆int导致只过了一半用例。
4.2 排序算法:笔试中不一定直接考但经常作为前置步骤
“冒泡排序算法C++”是热词里的常客,但说实话,笔试编程题直接让你手写冒泡排序的概率极低,更多是把排序作为整个算法流程中的一环。比如题目要求“按优先级从高到低输出任务,相同优先级的按编号升序”,这就需要在排序时写自定义比较函数。
不过这不代表不用掌握排序算法的内部实现。选择题时常考排序算法的稳定性、时间复杂度和适用场景。冒泡排序是稳定排序,选择排序是不稳定排序,快速排序最坏情况下退化成O(n^2),归并排序是稳定且O(n log n)。这些结论要记牢。
手写一份能过的快速排序代码如下:
void quickSort(vector<int>& nums, int left, int right) { if (left >= right) return; int i = left, j = right; int pivot = nums[(left + right) / 2]; while (i <= j) { while (nums[i] < pivot) ++i; while (nums[j] > pivot) --j; if (i <= j) { swap(nums[i], nums[j]); ++i; --j; } } quickSort(nums, left, j); quickSort(nums, i, right); }笔试中如果你需要排序,直接调用std::sort就好,但在自定义比较时要注意严格弱排序。比较函数中如果出现相等元素返回true的情况,会导致sort出现未定义行为,程序可能直接崩溃。这是笔试中一个非常隐蔽的坑,我之前就因为写了一个不满足严格弱排序的比较函数,在本地怎么跑都正常,OJ上却反复出问题。
4.3 单调栈:吃透“下一个更大元素”这一整类题
热词中“单调栈算法C++”上榜,说明很多人在校招准备阶段被这类题卡过。单调栈的典型应用场景是:在一个数组中,找每个元素左边/右边第一个比它大/小的元素。它能把这类问题的复杂度从O(n^2)优化到O(n)。
核心思路很简单:维护一个栈,让栈内元素保持单调递增或递减。以“找每个元素右边第一个比它大的元素”为例,从左到右遍历数组,当当前元素大于栈顶元素时,栈顶元素右侧第一个比它大的元素就是当前元素,弹出并记录答案。
笔试中单调栈的变种很多,但骨架基本一致。比如“柱状图中最大的矩形”、“接雨水”、“每日温度”这些题,背后都是单调栈。建议备考时把这几个题各写一遍,总结出模板:
vector<int> nextGreater(vector<int>& nums) { int n = nums.size(); vector<int> ans(n, -1); stack<int> st; for (int i = 0; i < n; ++i) { while (!st.empty() && nums[st.top()] < nums[i]) { ans[st.top()] = nums[i]; st.pop(); } st.push(i); } return ans; }要注意的是栈里存的是下标而不是值,因为我们不仅需要知道右侧最大值,还需要知道它的位置,这在很多变种题里是拿分的关键。单调栈题目一旦理解了单调性维护的本质,其实不怎么需要死记硬背,见到“下一个更大/更小”就反射性地想到单调栈。
4.4 字符串与数组的初始化、读取和转换
“C++字符串数组初始化”、“C++字符串转数组”、“C++ string库”这些搜索词反映出很多人在字符串处理上基础不牢。校招笔试的编程题里面,字符串处理是当之无愧的第一大题型,基本上每场考试都会出现至少一道。
先区分两个基本概念:C风格字符串和std::string。C风格字符串是以'\0'结尾的字符数组,比如char str[] = "hello",它的长度是6而非5,因为末尾要放结束符。std::string是C++标准库中的字符串类,底层是一个动态管理的字符数组,用户可以把它当成一个封装好的容器来用。
题目中常见的需求是把一个字符串按分隔符拆成若干子串。C++标准库没有现成的split函数,所以笔试前建议自己封装一个:
vector<string> split(const string& s, char delim) { vector<string> res; string cur; for (char c : s) { if (c == delim) { res.push_back(cur); cur.clear(); } else { cur.push_back(c); } } res.push_back(cur); // 不要忘了最后一截 return res; }这个函数虽然简单,但笔试现场临时写容易漏掉最后一截子串。用一个小时提前封装好,考试时直接调用,心里会踏实很多。
字符串转数字可以用stoi、stol、stoll,数字转字符串用to_string。但有一个坑是stoi在字符串无法转换时会抛出std::invalid_argument或std::out_of_range异常,如果不捕获就会导致程序崩溃,OJ直接判RE。所以在笔试编程题中如果发现输入数据可能不符合预期格式,要么做好异常捕获,要么自己手动逐字符转换,不要依赖stoi的默认行为。
C++字符串数组初始化这块也是一个经典易错点。C++11开始支持花括号初始化数组:
vector<string> names = {"alice", "bob", "charlie"};而C风格字符串数组则是:
const char* names[] = {"alice", "bob", "charlie"};这两个写法在笔试选择题中经常出现。注意vector版本可以直接用names.size()获取大小,C风格版本需要自己用sizeof(names)/sizeof(names[0])计算,如果是在函数参数传递的场景,sizeof会退化成指针大小,这就是经典笔试判断题。
5. 从笔试到实战:环境配置与代码习惯
5.1 本机搭建C++开发调试环境
笔试准备阶段,本地环境是否顺手直接影响刷题效率。“vscode配置c/c++环境”、“c/c++构建”、“microsoft visual c++ redistributable”这些热词反映了大家在环境搭建上的痛点。
我自己的建议是:如果是准备校招笔试,不要花太多时间折腾过于复杂的IDE,用VS Code + GCC/Clang就足够。核心步骤就三步:装编译器、装VS Code扩展、配置tasks.json和launch.json。
编译器这里有两种选择:Windows上推荐MinGW-w64的g++,或微软的MSVC。这两种对应了不同的工具链,语法基本一致,但链接库的路径、调试器的配置方式不同。如果你的代码只在OJ上跑,用MinGW-w64就够,它轻量、启动快、兼容性好。如果你还要在本地跑Windows原生图形程序或者用微软的调试工具,那就装Visual Studio Community。
这里还要提醒一个基础知识:很多同学把“Microsoft Visual C++ Redistributable”和“Visual C++编译器”搞混。Redistributable只是运行时库,它本身不包含编译器,装它只是为了运行依赖MSVC运行时库的程序。笔试环境一般不需要你安装运行库,但本地用MSVC编译出来的程序换到别的机器上跑时,目标机器可能需要对应版本的Redistributable。这个知识点虽然不直接计入笔试分数,但面试聊到项目部署时可能会被问到。
VS Code配置C++环境时,最常见的错误是tasks.json中的command路径写错,或者args中的编译选项不一致。一个可用的最小配置片段如下:
{ "tasks": [ { "label": "C++ Build", "type": "process", "command": "C:/mingw64/bin/g++.exe", "args": [ "-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}.exe" ], "group": "build" } ] }配置完成后按Ctrl+Shift+B编译,按F5调试,调试器用gdb。实际刷题时我习惯直接用终端命令编译运行,其实很多时候比VS Code的图形界面更快:
g++ -std=c++17 -O2 -Wall main.cpp -o main ./main < input.txt > output.txt这里我强烈建议刷题时养成用输入输出文件重定向的习惯。笔试平台的代码要自己处理输入输出,所以平时就习惯从input.txt读数据、把结果写到output.txt,上考场时你才不会对cin >> a和while (cin >> a)这种读取方式感到陌生。
5.2 笔试中容易踩的编译与内存坑
编程题写对了算法,却因为编译细节挂掉,是最冤的。我总结了几个每年都有很多人踩的坑。
第一个是头文件问题。笔试现场很多时候允许直接使用#include <bits/stdc++.h>,因为牛客和赛码网都支持。但有些本地编译器不支持这个头文件,所以建议在本地也统一使用它来刷题,或者干脆把所有常用的头文件单独列出来,避免代码里只有一个万能头而对自己使用的容器来源一无所知。
第二个是main函数的返回值类型。标准写法是int main(),不要写成void main(),这在MSVC下允许但GCC会报警告,在校招OJ环境下可能直接编译失败。另一个相关坑是忘记return 0,虽然C++标准允许main函数省略return,但为了稳妥还是加上。
第三个是数组越界。STL的vector在越界访问时不一定报错,它会给出一个“未定义行为”,可能什么也不发生,也可能直接崩溃。笔试中更稳妥的做法是用at()替代operator[],因为at()会做边界检查并抛出异常。不过at()的性能比[]略低,笔试一般不会卡这个性能差距,保正确性更重要。
第四个是int溢出。前面提到过,乘法、累加、求斐波那契第n项这类操作非常容易溢出int。C++标准中int通常为32位,范围是-2147483648到2147483647,一旦溢出就是未定义行为,OJ上表现出来是“答案错误”而不是“编译错误”,非常难排查。所以,凡是可能涉及超过10^9的中间值,建议直接定义成long long。
5.3 用“小游戏”练手,把C++写顺
热词里赫然列着“c++小游戏”、“c++好玩的代码”、“c++爱心代码”,这些搜索热度其实暴露了一个事实:很多人在学C++时感觉枯燥,需要一些有趣的小项目来维持动力。
我非常推荐用控制台小游戏作为笔试之外的调剂性练习。比如猜数字、扫雷、贪吃蛇、五子棋、2048,这些都适合用纯C++实现,代码量不大但是能覆盖数组、循环、函数、随机数、输入输出处理这些笔试选择题也会考的基础点。
拿猜数字来说,核心逻辑就是生成一个随机数,然后循环读取用户输入并给出反馈。这里有一个笔试也常考的点:C++里生成随机数应该使用std::mt19937而不是rand(),因为rand()的随机质量不高且受实现限制。虽然笔试选择题不一定会考到引擎选择,但用最新方式写代码是体现你专业度的重要细节。
#include <iostream> #include <random> int main() { std::mt19937 gen(std::random_device{}()); std::uniform_int_distribution<int> dist(1, 100); int target = dist(gen); int guess; while (std::cin >> guess && guess != target) { if (guess > target) { std::cout << "too big" << std::endl; } else { std::cout << "too small" << std::endl; } } std::cout << "bingo" << std::endl; return 0; }这种小项目做三五个之后,你对字符串输入、循环退出、类型转换的熟练度会大幅提升。很多同学刷笔试真题刷到麻木,不妨换个思路去做点小游戏,练完再回头看笔试选择题,会发现很多“语法题”其实就是小项目里踩过的坑。
6. 考的不仅是C++,更是复盘能力
6.1 笔试后的复盘方法
笔试结束并不意味着这个环节就翻篇了。不管考得好不好,我都建议当天晚上就把整个考试过程复盘一遍,因为在考场上你记忆最深、题目还原度最高。过了24小时再回忆,很多细节就模糊了。
复盘的第一步是记录题目和考点。笔试不像面试,通常不会公布题目,平台也看不到具体答案,但你可以在考后凭记忆把题目大致还原出来,并标注每道题考察的知识点和你的卡点。这个过程很有价值,因为它帮你提炼出了自己的薄弱环节:是选择题八股文不会,还是编程题超时,还是因为输入输出浪费了大量时间?
第二步是总结经验教训。比如“选择题花了50分钟导致编程题只剩半小时”这类时间管理问题,就要在下一次笔试前刻意训练。如果你发现自己在“字符串转数组”这种基础操作上还需要现场查API,那就说明基础不牢,需要从热词里列出的那些高频知识点开始补。
第三步是把每一道没做出来的编程题重新在本地代码库里实现一遍,并且贴上“网易2023笔试复盘”这种标签。等到你积累了10场笔试的复盘内容后,会发现自己对网易这类公司的出题风格已经形成了肌肉记忆。
6.2 常见学习与面试问题速查
笔试和面试其实是高度关联的,笔试过了还有一面、二面,每一面都可能在笔试内容的基础上继续深挖。我在校招季经常被问到的几个问题,顺带放在这里供大家自查。
“为什么vector比list查找快?”这个问题的标准回答模板是:因为vector底层是连续内存,支持O(1)随机访问,CPU缓存命中率高;list底层是双向链表,只能顺序访问,且每个节点存储额外的前后指针,缓存局部性差。简单来说就是“连续内存+缓存友好”。
“shared_ptr和unique_ptr的使用场景如何选择?”答案是优先用unique_ptr,因为开销更低、语义更清晰;只有需要多个对象共享所有权的时候才用shared_ptr。这里还可以接一个经典反问:“shared_ptr的引用计数本身是线程安全的,但指向的对象不是,你如何理解?”能说出来这一点,面试官通常会眼前一亮。
“constexpr和const的区别是什么?”const是运行时到编译期的常量约束,constexpr强制编译期求值。const可以修饰变量、函数返回值,constexpr则可以修饰变量和函数。笔试中经常用constexpr int N = 100; int arr[N];来考察编译期确定数组大小的概念。
这些问题的共同点是:它们不要求你背诵标准答案,而是要求你用“为什么”的思路把知识点串起来。准备笔试的时候如果时间紧张,先围绕这些高频问题做深度理解,比盲目刷题有用得多。
另外,笔试中如果遇到完全不会的局面,也有一个保底策略:写暴力解法拿部分分。网易笔试的判题规则一般按测试点给分,暴力法至少能通过小数据用例,能拿20%到40%的分数。不要觉得暴力解法丢人,校招笔试的目标是“分数最大化”,不是“写出最优解”。
还有一个小习惯值得养成:每次写完代码,停下来花30秒读一遍自己的代码,检查有没有拼写错误、变量名不一致、缺少头文件。在线OJ只能告诉你“答案错误”或者“编译错误”,它不会像本地编译器那样给出友好的错误提示。考前把代码检查清单固定下来,很多低级错误是可以完全避免的。
C++校招笔试这条路上,真正拉开差距的不是智商,而是准备的系统性和复盘的习惯。把C++底层的对象模型、内存模型和STL原理理解到位,把常见算法模板练成肌肉记忆,再加上充分的考后复盘,网易这样的大厂笔试并不会是迈不过去的坎。希望这份拆解能让你少走一些弯路,节省下来的时间,不妨继续去刷一道自己不太熟的题。
