我在招聘系统里看到“浩鲸科技2020届-C++-2”这个岗位编号时,第一反应是这届校招的C++岗位竞争比想象中更结构化——岗位被细分成多个批次,说明投递人数多、筛选维度细。再结合现在C++相关的热搜词,从vscode配置、字符串数组初始化、constexpr、冒泡排序、快速幂、单调栈、ABA问题、多线程、设计模式到C++八股文,几乎把校招面试的考点地图铺了一遍。
这篇内容不打算写成面面俱到的教科书,而是结合真实的校招准备路径,把C++从基础语法、算法刷题、并发与设计模式到工具链配置这些环节挨个拆开,说清楚每个考点背后的逻辑和面试官的真实意图。无论你是正在准备校招的应届生,还是想转C++方向的后端新人,这份梳理可以作为一份带避坑经验的学习索引。
1. C++校招岗位背后的准备路线图——从热搜数据看面试风向
1.1 热搜词里藏着三类需求:考点、环境坑和入门困惑
把C++相关的热搜词拉出来看一遍,能明显感受到三类人群的交叠。
第一类是面试考点类,比如constexpr、C++多线程、C++设计模式、回调函数、单调栈算法、快速幂算法、ABA问题。这些都是校招面试里真正会问的内容,而且难度梯度很清楚:constexpr是C++11引入的关键字,问的是编译期求值;多线程问的是锁、条件变量、原子操作;设计模式问的是单例、工厂、观察者在具体场景里的落地;快速幂和单调栈则是算法题里的常客。这些词高频出现,说明大量求职者在针对这些知识点做突击。
第二类是环境配置和运行库类,比如vscode配置c/c++环境、visual c++ redistributable、microsoft visual c++ redistributable。这类词看着像装机教程,实际反映的是很多新手在校招准备阶段,连开发环境都还没完全跑通。Visual C++红字库(VC++ Redistributable)被反复搜索,多半是运行某些软件或IDE时弹了“缺少MSVCP140.dll”之类的报错。这类问题虽然不是面试考点,但会直接影响刷题和写demo的效率,所以会挤进热搜。
第三类是入门阶段的语法困惑,比如c++字符串数组初始化、c++读入整行、c++结构体链表基本语法、c++字符串转数组。这些是C++学习路径上最早遇到的坎,也是面试手写代码时最容易暴露基本功的地方。很多人在LeetCode上能AC中等题,但面对面让手写一个链表的头插法,或者在白板上写出用getline读入整行的代码,会卡壳——原因就是这些基础语法没有形成肌肉记忆。
1.2 我的优先级排序:先把基础捞扎实,再谈加分项
结合我自己带项目、面试候选人的经验,C++校招准备不能平均用力。
我见过太多人花大量时间刷“C++面试题”“C++八股文”合集,结果面试官问了一个最简单的字符串拷贝就答不清楚。原因很简单:八股文合集覆盖的是“问题-答案”的知识点,但面试官真正考察的是“思路-实现-边界处理”的能力链路。所以我的建议是分四层推进:
- 第一层:语言基础。字符串、数组、指针、引用、结构体、链表、文件读写,这些必须能手写,不能只停留在“看过”。
- 第二层:面向对象与内存。构造函数、析构函数、拷贝控制、继承多态、虚函数表、内存布局,这些是C++区别于其他语言的核心,也是面试高频区。
- 第三层:算法与数据结构。数组、链表、栈、队列、哈希、二叉树、排序、二分、双指针、贪心、动态规划、单调栈,按专题刷。
- 第四层:并发、设计模式、网络与工程化。这部分属于拉开差距的内容,往往结合项目来问。
这个顺序的重要性在于:基础不牢,谈设计模式和多线程都是空中楼阁。比如设计模式里的单例模式,如果不理解C++11之后的call_once和局部静态变量初始化线程安全特性,写出来的双检锁单例可能还有内存序问题,这就是基础概念没打通的表现。
2. 语言基础别只背八股——字符串、链表、constexpr这些点怎么答才能过关
2.1 字符串数组初始化:一句话说清,手动写一遍
C++里字符串数组初始化是新人最容易犯迷糊的点,因为它有两种实现路径:C风格字符数组和C++的std::string。
先看C风格:
char str1[] = "hello"; // 编译器自动分配6个字节,末尾包含'\0' char str2[6] = "hello"; // 显式指定长度,必须比字符数多1 char str3[] = {'h', 'e', 'l', 'l', 'o'}; // 注意:这是5字节,没有'\0'char str3[] = {'h', 'e', 'l', 'l', 'o'};这种写法很容易出问题,因为缺少结束符'\0',后面用cout << str3或strlen(str3)时会越界读,输出不可预知的内容。我在实际调试中见过不少次这种bug,表现形式很诡异,有时候不报错,有时候随机多打印几个字符。
再看C++风格的字符串数组:
#include <string> #include <vector> std::string strs1[] = {"apple", "banana", "cherry"}; std::vector<std::string> strs2 = {"apple", "banana", "cherry"};用std::string的好处是自动管理内存,不用担心'\0'和越界。我自己刷题和写工程代码时,能用std::string就不用char[],除非是做底层网络协议解析、序列化或需要精确控制内存布局的场景。
面试如果问到这里,建议主动补充一句:C风格字符串的'\0'结束符至关重要,所有C字符串函数都依赖它,这是很多内存越界漏洞的根源。这句话能体现你对内存安全的敏感度。
2.2 读入整行与getline:面试手写代码最容易翻车的细节
“C++读入整行”这个热搜词背后的坑,其实藏得很深。
很多人在刷算法题时用cin >> s读字符串,但遇到“输入一行包含空格的字符串”就懵了。cin >> s按空白字符分隔,遇到空格就截断,所以一次只能读一个单词。要读整行,需要用getline:
#include <iostream> #include <string> std::string line; std::getline(std::cin, line); // 读一整行,包括空格但真正的坑在混用cin >>和getline的场景。比如:
int n; std::cin >> n; // 读入一个整数,但换行符还留在输入缓冲区 std::string line; std::getline(std::cin, line); // 读到的可能是空行!因为cin >> n读完数字后,换行符'\n'仍然残留在缓冲区里,紧接着的getline读到这个换行符就返回了。解法是读完数字后加一句std::cin.ignore();,或者用std::getline把换行符先吃掉。
这类问题面试官很喜欢在白板题里埋雷,因为看起来简单,但真正手写时很容易忽略缓冲区残留的问题。我在面试候选人时也会故意在题目里设置这种输入格式,能稳住的几乎都是有真实编码量的。
2.3 结构体链表的底层:链表操作一定要能裸写
C++结构体链表基本语法是入门题,但校招面试里手写链表操作已经成了保留项目。值得注意:现在选择题里出现[gesp202603 七级] 物流网络这类较新的竞赛题,说明链表的考察形式越来越灵活。
最基础的链表节点:
struct ListNode { int val; ListNode* next; ListNode() : val(0), next(nullptr) {} ListNode(int x) : val(x), next(nullptr) {} ListNode(int x, ListNode* next) : val(x), next(next) {} };必须能裸写的三个操作是:头插法、尾插法、反转链表。头插法最容易出错的地方是顺序:
// 头插法,newNode插入到head前面 newNode->next = head; head = newNode;顺序不能反过来,如果先改head再改newNode->next,原来的链表就丢了。
反转链表的迭代写法也是高频手写题:
ListNode* reverseList(ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr) { ListNode* nextTemp = curr->next; curr->next = prev; prev = curr; curr = nextTemp; } return prev; }这段代码的逻辑是三指针交替,关键是nextTemp必须先保存,否则curr->next被改写后就找不回原链表了。类似的“先保存后修改”思路在二叉树、图遍历里也高频出现,属于C++指针操作的通用套路。
2.4 constexpr的演进:从C++11到C++17的变化
热搜词里有“constexpr哪个c++版本引入的”,这个问题本身很简单——C++11。但面试如果只答到这里,基本拿不到分。面试官真正想确认的是你是否理解constexpr的语义变化。
C++11时代,constexpr只能修饰简单的函数,函数体只能有一条return语句,不能用循环、局部变量、分支。到C++14就放宽了限制,可以在constexpr函数里用局部变量、循环和分支了。C++17进一步引入了if constexpr,可以在编译期做条件判断,这极大地增强了模板元编程的表达力。
一个实际例子:
// C++11风格,函数体只能一行return constexpr int square_cxx11(int x) { return x * x; } // C++14及之后,可以用局部变量和循环 constexpr int factorial_cxx14(int n) { int result = 1; for (int i = 2; i <= n; ++i) { result *= i; } return result; }传统const和constexpr的区别在于:const表示“运行期不可修改”,而constexpr表示“编译期可求值”。前者修饰的对象可以是运行时变量,后者要求必须在编译期算出结果,所以constexpr可以用来定义数组大小、模板非类型参数等场景。
面试答题策略建议:先答版本,再补语义演进,最后给一个if constexpr的模板应用例子。三步走下来,这个考点就能从“背诵”变成“有深度的回答”。
3. 算法题的热身顺序——从冒泡排序到快速幂、单调栈
3.1 冒泡排序和选择排序:为什么面试官还在问
“冒泡排序算法c++”“选择排序c++”这类词能在热搜里长期占位,说明大部分人的算法学习都从这两个最基础的排序开始。但面试官问冒泡排序,不是为了考你会不会写,而是看你会不会优化。
基础版的冒泡排序:
void bubbleSort(std::vector<int>& arr) { int n = arr.size(); for (int i = 0; i < n - 1; ++i) { for (int j = 0; j < n - 1 - i; ++j) { if (arr[j] > arr[j + 1]) { std::swap(arr[j], arr[j + 1]); } } } }这个写法时间复杂度是O(n^2),但面试时应主动补一个优化:加一个标志位,如果某一轮循环没有发生任何交换,说明数组已经有序,可以提前退出。
void bubbleSortOptimized(std::vector<int>& arr) { int n = arr.size(); for (int i = 0; i < n - 1; ++i) { bool swapped = false; for (int j = 0; j < n - 1 - i; ++j) { if (arr[j] > arr[j + 1]) { std::swap(arr[j], arr[j + 1]); swapped = true; } } if (!swapped) break; } }这个优化在最好情况下能把时间复杂度降到O(n)。面试时主动写出这个优化版本,会让面试官觉得你理解排序的本质,而不只是背代码。
3.2 最小公倍数:从gcd推导到lcm的数学实现
热搜词里有“n个整数的最小公倍数怎么求c++”,这是少数关键词,问题很具体。最小公倍数的核心是先求最大公约数(GCD),然后利用公式:两数的最小公倍数等于两数乘积除以最大公约数。
int gcd(int a, int b) { while (b != 0) { int temp = b; b = a % b; a = temp; } return a; } int lcm(int a, int b) { return a / gcd(a, b) * b; // 先除再乘,防止溢出 }注意代码里的细节:a / gcd(a, b) * b是先除后乘,而不是a * b / gcd(a, b)。原因是a * b可能溢出int范围,先除能降低溢出风险。这个细节非常小,但能反映你写生产级代码的素养,面试时值得专门提一句。
扩展到n个整数的情况:
int lcmOfArray(const std::vector<int>& nums) { int result = 1; for (int num : nums) { result = lcm(result, num); } return result; }这个累乘式求次最小公倍数的过程,本质是结合律的应用,面试不会问得太深,但能流畅写出并解释原理,就能在“数学基础”这一项上拿分。
3.3 快速幂:二分思想在算法题里的典型应用
快速幂算法能进热搜,是因为它是从“暴力”到“优化”思维转变的经典例题。算a^n,暴力方法是循环n次相乘,时间复杂度O(n)。快速幂利用二分思想,把指数按二进制拆解,时间复杂度降到O(log n)。
递归版本:
long long fastPow(double a, int n) { if (n == 0) return 1; if (n % 2 == 1) { return a * fastPow(a, n - 1); } else { long long half = fastPow(a, n / 2); return half * half; } }迭代版本更推荐,因为避免了递归栈开销,也更好理解:
long long fastPowIter(double a, int n) { long long result = 1; long long base = a; while (n > 0) { if (n & 1) { // 当前二进制位是1 result *= base; } base *= base; // 基数平方 n >>= 1; // 右移一位 } return result; }快速幂的价值不只是这一道题,它背后的“二进制拆解”思想还能用到矩阵快速幂(斐波那契数列优化)、状态压缩DP等场景。面试如果问“你还会哪些快速幂的应用”,能答出“矩阵快速幂加速斐波那契到O(log n)”会是一个很好的加分点。
3.4 单调栈:一类套路题的模板与变体
单调栈算法在热搜里频繁出现,因为它是一类题型的“万能钥匙”。单调栈的核心思想是:维护一个单调递增或递减的栈,用于快速找到某个元素左边或右边第一个比它大(或小)的元素。典型应用是“下一个更大元素”问题。
模板:
// 找到每个元素右边第一个比它大的元素,返回索引数组 std::vector<int> nextGreaterElement(const std::vector<int>& nums) { int n = nums.size(); std::vector<int> result(n, -1); std::stack<int> stk; // 存索引,从栈底到栈顶单调递减 for (int i = 0; i < n; ++i) { while (!stk.empty() && nums[i] > nums[stk.top()]) { result[stk.top()] = i; stk.pop(); } stk.push(i); } return result; }很多人在初学这个算法时卡在“为什么要用栈”上。生活化类比是这样的:想象一排人站在一起,每个人都在找自己右边第一个比自己高的人。从左边开始,个子矮的人先入栈等结果;遇到一个高个子,则栈里所有比它矮的人都能确定答案了,出栈;然后这个高个子入栈,继续等待下一个更高的人。这个过程每个元素最多入栈一次、出栈一次,总时间复杂度O(n)。
单调栈的变体很多,比如接雨水(LeetCode 42)、柱状图中最大的矩形(LeetCode 84)、每日温度(LeetCode 739)。建议每个变体都敲一遍模板,识别单调性是递增还是递减,然后对比它们处理边界条件的差异。
4. 多线程、设计模式与回调——拉开差距的加分地带
4.1 C++多线程基础:从thread到条件变量
C++多线程在热搜里是高频词,也是校招面试里最容易拉开差距的考点。问得比较多的包括:std::thread的基本用法、std::mutex与std::lock_guard的区别、std::atomic和std::condition_variable的使用场景。
基础用法:
#include <thread> #include <mutex> #include <iostream> std::mutex mtx; int counter = 0; void increment() { for (int i = 0; i < 1000000; ++i) { std::lock_guard<std::mutex> lock(mtx); ++counter; } } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << counter << std::endl; // 输出 2000000 return 0; }这里std::lock_guard比手动lock()/unlock()更安全,因为即使中途抛异常,锁也会在栈展开时自动释放,避免死锁。面试如果要写“手写一个线程安全的计数器”,用lock_guard是最稳妥的。
多线程的进阶考点还包括:
std::unique_lock:比lock_guard更灵活,可以延迟加锁、手动解锁、与条件变量配合。- 死锁的产生条件与规避:互斥、持有并等待、不可剥夺、循环等待。面试名题“哲学家就餐”就是在讲这个。
std::atomic:适用于简单的计数器场景,比mutex性能更高。
4.2 ABA问题:CAS并发模型里的经典坑
“aba问题c++”能上热搜,说明不少人在准备并发面试时被这个问题卡住了。
ABA问题的背景是CAS(Compare-And-Swap,比较并交换)操作。CAS的思路是:比较内存中的值与期望值是否相等,如果相等就更新为新值,否则不做操作。这个操作是原子的,在多线程环境下可以用来实现无锁数据结构。
但CAS有一个经典缺陷:如果内存中的值从A变成B,又变成A,那么CAS会认为值没有变化过,从而忽略中间状态的变化,可能导致数据错误。这就是ABA问题。
举个例子:一个栈顶是A,线程1准备执行CAS,把栈顶从A换成B。在它执行之前,线程2把栈顶A弹出,压入C和B,最后栈顶又变成B;然后线程3把B和C弹出,重新压入A。此时线程1的CAS发现栈顶还是A,替换成功,但栈的实际结构已经变了,可能造成丢失了中间节点的错误。
解决ABA问题最常用的方法是引入版本号或标记位。每次修改值的同时修改版本号,CAS时同时比较值和版本号,值相同但版本号不同则说明发生过修改。C++里可以用std::atomic<std::pair<uintptr_t, size_t>>或者std::atomic<std::shared_ptr<T>>实现带版本的原子指针。实际工程里,最直接的办法是加锁,避免盲目追求无锁。
4.3 设计模式在C++里的落地:单例与工厂的线程安全
“C++设计模式”是热搜词,但校招面试很少让你背23种设计模式的定义,更多是结合实际问单例、工厂、观察者、策略这类高频模式的实现。
单例模式几乎是必考题。基础懒汉式单例的线程安全问题值得重点关注。
C++11之后最推荐的写法是使用局部静态变量,它天然线程安全:
class Singleton { public: static Singleton& getInstance() { static Singleton instance; return instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() {} ~Singleton() {} };C++11标准保证局部静态变量的初始化是线程安全的,所以这段代码不需要加锁就能在多线程环境下正确工作。这个写法比双检锁(Double-Checked Locking)更简洁,也比饿汉式更延迟加载。面试被问到单例,建议先用这个写法,再解释为什么它线程安全。
工厂模式则更偏向面向对象的设计技巧,简单工厂、抽象工厂都要知道适用场景。面试官通常会问:“如果新增一种产品类型,你的工厂需要改动哪些代码?”答案的要点在于,利用多态和虚函数,让新增类型只增加子类,不改动工厂核心逻辑。
4.4 回调函数:从函数指针到std::function与lambda
“c++回调函数例子”能进热搜,说明很多人对“回调”这个概念的理解停留在抽象层,无法给出具体实现。回调函数的本质是:把一段可执行代码作为参数传给另一个函数,由后者在合适时机调用。
从C时代的函数指针说起:
#include <iostream> void onEvent(int code) { std::cout << "Event code: " << code << std::endl; } void trigger(void (*callback)(int)) { callback(42); } int main() { trigger(onEvent); return 0; }这种函数指针写法在C++里已经不算主流了,更现代、更灵活的方式是用std::function配合lambda表达式:
#include <functional> #include <iostream> void trigger(const std::function<void(int)>& callback) { callback(42); } int main() { int offset = 10; trigger([offset](int code) { std::cout << "Event code: " << code + offset << std::endl; }); return 0; }lambda通过[]捕获外部变量,可以按值[offset]或按引用[&offset]捕获,这比函数指针灵活得多,也是现代C++里回调的主力写法。
面试问回调时,可以主动提到回调在异步编程和事件驱动框架里的应用:网络库的OnMessage回调、定时器的OnTimer回调、UI框架的OnClick回调。这样能把概念落到工程场景,比解释定义有说服力得多。
5. 环境与工具链的坑——vscode配置、编译构建、DLL运行库
5.1 vscode配置C/C++环境:三个json文件的职责
“vscode配置c/c++环境”和“vscode c++编译so导出库”这两个热搜词反映出,很多准备校招的人在第一步就被开发环境卡住了。vscode配置C/C++本质上需要理解三个json文件的分工。
第一个是c_cpp_properties.json,负责IntelliSense,也就是代码补全、跳转、语法检查。这里最重要的是includePath,编译器头文件路径。很多人代码编译没问题,但vscode里满屏红色波浪线,就是因为这个文件的includePath没配好。
第二个是tasks.json,负责编译。使用g++编译单个文件时,task里要配置command为g++,args里写编译参数:
{ "version": "2.0.0", "tasks": [ { "label": "build hello", "type": "shell", "command": "g++", "args": [ "-g", "-o", "hello", "hello.cpp" ], "group": { "kind": "build", "isDefault": true } } ] }第三个是launch.json,负责调试。需要配置program字段指向编译出的可执行文件路径,miDebuggerPath指向gdb(Linux/macOS)或gdb.exe(Windows)。
一个常见的陷阱是只配置了tasks.json没配置launch.json,导致点F5调试时提示找不到可执行文件。这就是因为没有告诉调试器去哪里找编译产物。解决方法是先在终端里编译出可执行文件,再在launch.json的program字段里写对路径,注意路径分隔符要正确转义。
5.2 从源码到可执行文件:编译链接的基本流程
“c/c++构建”“c/c++ 编译器”这两个热搜词,指向的其实是编译链接的基本流程问题。
一个C++源文件变成可执行文件要经过四个阶段:预处理、编译、汇编、链接。面试里被问到的概率也很高。
- 预处理:展开
#include、宏定义替换、条件编译。可以用g++ -E查看预处理后的结果。 - 编译:把预处理后的代码翻译成汇编语言。用
g++ -S生成.s文件。 - 汇编:把汇编代码翻译成机器码,生成
.o目标文件。用g++ -c。 - 链接:把多个目标文件和库文件合并成可执行文件。也就是
g++ main.o utils.o -o app这一步。
新手写多文件项目时最容易遇到的错误是“未定义的引用”(undefined reference to ...)。这个错误通常不是编译错误,而是链接阶段找不到函数定义,原因可能是:忘记编译某个.cpp文件、忘了链接某个库(用-l指定库名)、头文件里只声明了函数但没实现。
理解这四个阶段有助于解释很多面试题,比如头文件里的#include为什么不要放函数定义(可能导致多重定义链接错误),静态库和动态库的区别,以及vscode c++编译so导出库里“导出”的含义——导出的是符号,让外部程序能调用so里实现的函数。
5.3 Microsoft Visual C++ Redistributable:装机必备的DLL运行库
“Microsoft Visual C++ Redistributable”相关热搜词,说明大量用户在安装软件时被运行库问题卡住过。这是Windows平台特有的坑,但校招面试偶尔也会被问到“运行库和开发库的区别”。
Visual C++ Redistributable是微软提供的C++运行时组件集合,包含MSVCP140.dll、VCRUNTIME140.dll等DLL文件。用Visual Studio编译的C++程序在运行时会动态链接这些DLL,如果目标机器上没装对应版本的运行库,程序启动时会弹窗报错“缺少MSVCP140.dll”或“代码执行无法继续,因为找不到VCRUNTIME140.dll”。
在测试环境或面试演示平台上遇到这类报错,不要慌,下载对应版本的Redistributable安装即可。但更重要的是理解产生原因:程序编译时选择“动态链接”C++运行库,所以发布时需要带上运行库;如果选择“静态链接”就不需要带,但可执行文件体积会变大。
在Windows上用vscode配置C++环境时,如果用的是MinGW-w64或MSYS2的g++编译器,一般不依赖VC++ Redistributable,因为这两个工具链默认链接的是MinGW运行时库。如果你的开发环境是Visual Studio或MSVC构建工具,则要注意运行库的名称是MSVCP140.dll。这个差异也解释了为什么有些人电脑上没装VC++运行库,但用g++编译的程序运行正常。
6. 从笔试到现场——C++岗位面试的全流程复盘与临场建议
6.1 笔试环节:时间分配比刷题数量更重要
校招笔试通常包含选择题和编程题两部分。C++方向的选择题往往覆盖三类:语言细节(constexpr、虚函数表、内存对齐)、算法复杂度分析、计算机基础(操作系统、网络、数据库)。这部分没有速成捷径,就是靠平时的积累和针对性的刷题。
编程题的时间分配建议:先快速浏览所有题目,按难度排序,从最简单开始做,保证保底分。不要在一道题上死磕超过30分钟,先把会做的写完,再回来思考难题。我见过不少人在一道动态规划题上耗掉一小时,导致后面简单的字符串处理题都没时间写,这是最大的失败原因。
笔试前建议做几套历年真题,重点关注时间分配和典型输入输出格式(比如读入整行、多组测试数据、用逗号分隔的输入)。这些细节如果到考场上才第一次遇到,会浪费大量时间在调试输入输出上。
6.2 手撕代码的细节:面试官到底在看什么
现场手写代码是C++校招面试的标配环节。作为面试官,我在看候选人手撕代码时不只看结果对不对,更看三个维度。
第一是思路是否清晰。拿到题目后,先跟面试官确认输入输出边界,然后口头说一遍算法思路和数据结构的复杂度,再动手写。这个“先说后写”的过程能让面试官知道你在编码前有全局思考。
第二是代码风格。变量命名有意义、函数职责单一、没有魔法数字,这些体现的是工程素养。面试时不要求写出生产级代码,但也不能把变量全命名为a、b、tmp,面试官看着很痛苦。
第三是边界处理。链表判空、数组越界、整数溢出、空指针,这些问题最容易成为代码里的隐藏bug。写完代码后主动用几个测试用例在心里跑一遍,检查边界条件,这个过程本身就是加分项。
手撕代码翻车也不需要太慌,关键是要表现出调试的能力。面试官通常会给提示,这时候能根据提示快速定位问题、修正代码,也是过关的关键。怕的是一声不吭、陷入僵局、又不沟通。
6.3 面试完要做的事:错题本与复盘
很多校招候选人的一个误区是面完就撒手不管,结果同一类问题在下一场面试里再次丢分。我自己的做法是每次面试后,趁记忆新鲜,立刻把面试中问到的题目和回答情况记录下来,整理成错题本。这个过程也是知识内化的过程。
错题本要记录三个维度:
- 题目是什么:尽量还原原题描述,包括边界条件。
- 当时怎么答的:记录自己的回答思路和卡壳点。
- 正确思路是什么:查资料后补充正确的解法或更优答法。
如果当场被问住了,面试结束后一定要立刻查漏补缺。比如面试官问了一个关于std::unique_ptr和std::shared_ptr区别的问题,你答得不完整,那就要把智能指针的底层实现、引用计数机制、循环引用问题全部过一遍,确保下次被问到时能答得深入。
我自己在实际参与技术面试时最看重的,是候选人能不能把“听说过”变成“能解释、能落地、能讲清楚细节”。校招岗位、笔试面试都只是起点,真正的分水岭在于持续的学习习惯和工程实践。如果你也正在准备C++方向的技术笔试和面试,先把基础语法过一遍,再按照算法专题、多线程、设计模式、工具链的顺序逐一攻克,每一层都要动手写代码验证,不要只停留在“看懂了”的阶段。哪怕每天只完整吃透一个知识点,积累一个月,效果也会非常可观。