ARTICLE DETAIL

资讯详情

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

C++笔试题高效整理指南:从高频考点到实战策略

C++笔试题高效整理指南:从高频考点到实战策略 每年到招聘季都会有人抱着一堆散落收藏夹的链接来问我“C笔试题到底怎么整理才有效”我自己当年也经历过那种状态浏览器里躺着几十篇博客今天看虚函数明天看排序到最后什么都是“好像看过又好像没看过”。后来把这两年准备C笔试题的笔记重新过了一遍发现真正的问题不是题目不够多而是没有把知识点按考察逻辑串起来。这篇文章就围绕“C笔试题整理”这件事把我实际用得上的整理思路、高频考点和应对方法拆开说清楚。不管你是马上要参加校招笔试的应届生还是想跳槽到偏底层、偏基础软件岗位的工程师只要目标是C方向这篇都能帮你少走一点弯路。1. 内容整体设计与思路拆解1.1 为什么C笔试题值得认真整理很多公司尤其是基础软件、高性能计算、游戏引擎、嵌入式这些方向依然把C作为笔试的主要考察语言。原因很简单C本身横跨语言基础、内存管理、面向对象、模板、STL、算法与数据结构多个层次一个人基础扎不扎实几道笔试题就能探出来。大家常说的“C八股文”表面看是背题目实际上是要你真正驾驭这套语言机制。题目翻来覆去就是那几个核心点但每个点都能往深了问。认真整理笔试题的真正收益不是背下多少道题的答案而是通过题目把知识框架搭起来。答对一道选择题容易能把每个错误选项为什么错讲清楚才说明你理解了。整理的过程就像是给自己画知识地图先有主干再补枝叶。我见过不少朋友刷题刷了大几百道结果问他“构造函数里能不能调用虚函数”还是含含糊糊。这就是只记题目没建框架的结果。1.2 高频考点地图这八类优先级最高根据我对大量C笔试题的观察考点基本集中在八个方向语言基础指针、引用、const、static、关键字作用域内存管理堆与栈、new/delete、malloc/free、智能指针面向对象构造函数、析构函数、继承、多态、虚函数STL与泛型vector、map、sort、模板、迭代器失效算法与数据结构排序、二分查找、字符串处理、链表、二叉树编译与运行环境预处理、编译链接、静态库与动态库、C/C运行库C新特性C11/14/17的智能指针、移动语义、lambda、constexpr并发与操作系统基础线程、锁、内存模型、进程地址空间优先级上第一梯队是内存管理、面向对象、算法与数据结构这三个方向出现的频率最高分值也最重。第二梯队是STL与编译原理因为工程中用得多笔试也常带一两道。第三梯队是新特性和并发通常以选择题或填空题出现但大厂面试里比重在上升。1.3 笔试题的常见题型与应对逻辑C笔试题大致分三类每类的备考侧重点完全不同。题型考察能力备考重点选择题/多选题语言细节的精确度const、static、指针、关键字、运算符优先级改错题/代码分析题代码阅读与调试能力内存泄漏、数组越界、未定义行为、拷贝构造编程题逻辑与代码落地能力排序、二分、字符串、链表、二叉树很多人在选择题上栽跟头是因为只记结论不记原理。比如“const int* p”和“int* const p”到底哪个指针不能变看起来简单换个问法立刻有人懵。整理的时候我的方法是每道题不管对错都把四个选项涉及的知识点分别写一句解释这样一道选择题等于复习了四个小知识点。改错题则需要训练对代码的敏感度看到裸指针先想谁释放看到数组下标先想越界看到递归先想终止条件。编程题则是另一个世界重点在动手能力和边界意识下一章会展开聊。2. 高频基础题从编译内存到对象模型2.1 指针与引用以及const的多个位置指针和引用是第一道大菜几乎每套笔试题都会出现。核心区别要脱口而出指针是一个变量存的是地址可以重新赋值指向别处引用是一个已存在对象的别名必须在定义时初始化之后不能再绑定到其他对象。底层实现上引用通常就是个指针常量但语义上它比指针更安全因为不存在空引用。笔试里最常挖坑的是const和指针的组合。我建议记一条简单的规律const修饰的是它左边最近的那个类型如果左边没有就往右看。比如“const int *p”const右边是int说明p指向的int值不可变但p本身可以指向别处而“intconst p”const左边是int说明指针本身不可变但指向的int值可以改。还有一种“const int *const p”两者都不可变。考题经常给一段代码问哪行编译报错想清楚这个规律基本不会错。引用也有一个高频考点函数传参时什么时候用传值、什么时候用传引用、什么时候用const引用。大对象一定用const引用避免拷贝开销需要修改实参才用非const引用如果函数内部要保存对象副本那就直接传值配合移动语义效率也不差。这种问题笔试题里未必直接考但面试官特别喜欢顺着笔试题往下追问。2.2 构造函数、析构函数、拷贝控制的完整链条构造函数这个知识点笔试喜欢考“这个对象是怎么被创造出来的”。一个类可以有无参构造、有参构造、拷贝构造、移动构造还可能被编译器隐式生成。我们要搞清楚什么时候编译器会生成默认构造只要存在任何用户自定义的构造函数编译器就不再生成无参构造。拷贝构造什么时候被调用函数传参、函数返回值、直接初始化都可能触发很多人以为赋值也算其实赋值是另一个问题。析构顺序也是常考点。局部对象按构造的逆序析构成员对象按声明顺序析构基类在派生类之后析构。笔试题里经常给一个多继承或嵌套对象的例子让你写出析构打印的序列这时候按照“先构造的后析构基类最后析构”的规则一步步推就行。我整理题目时把这些规则都写在笔记本首页考前扫一眼就能快速回忆起来。深拷贝与浅拷贝是笔试中很容易丢分的地方。默认拷贝构造做的是逐成员拷贝对int这种普通类型没问题但如果类里有裸指针两个对象会指向同一块堆内存析构时就会double free。正确做法是自定义拷贝构造和拷贝赋值或者直接用智能指针、vector这类管理好内存的类型。现在很多公司笔试会出一个“这个类需要哪些函数才能正确管理资源”的题核心就是在考这条规则。2.3 new/delete与malloc/free的不同这个老生常谈的问题几乎必考但它们的不同点要做到一条不落。malloc/free是C语言的库函数只分配和释放指定字节的内存不做初始化工作new/delete是C运算符new在分配内存后会调用构造函数完成对象初始化delete会先调用析构函数再释放内存。new返回的是类型化指针malloc返回void*需要强制类型转换。往深了说new的底层实现是调用operator new而operator new内部通常用malloc来获取内存所以可以说malloc是更底层的机制。new分配失败时抛出bad_alloc异常malloc失败时返回NULL这一点在笔试题里也常被拿来问。还有一点是匹配问题new[]一定要配delete[]new配delete否则行为未定义。很多老代码里的崩溃就出在这种不匹配上笔试改错题里特别喜欢埋这个雷。另外operator new和operator delete是可以重载的这在内存池、对象池这类性能敏感场景里很常见。笔试如果考到这一层一般不会要求手写完整实现但至少要知道重载的入口长什么样以及为什么类级别的operator new会被优先查找。2.4 内存布局与常见内存错误内存布局题在笔试里也很常见。一个进程的虚拟地址空间从低地址到高地址大致是代码段、数据段、BSS段、堆区、内存映射区、栈区、内核空间。局部变量和函数调用在栈上栈往下生长动态分配的内存来自堆堆往上生长。栈上的对象作用域结束就自动析构堆上的对象必须手动释放或用智能指针管理。C里最常考的内存错误无非这几种数组越界、使用未初始化指针、释放后继续使用、重复释放、内存泄漏。笔试改错题里看到malloc/new就知道要找释放配对看到memcpy/strcpy就要检查缓冲区够不够大看到裸指针在容器里转来转去就要想到生命周期由谁负责。智能指针是解决这类问题的现代手段unique_ptr独占所有权shared_ptr共享所有权weak_ptr用来打破循环引用。关于shared_ptr还有一个高频考点两个shared_ptr互相引用会导致引用计数永远不为零造成内存泄漏解决办法是用weak_ptr。3. 面向对象与多态核心虚函数与继承3.1 虚函数、虚函数表与动态绑定虚函数是C笔试的重灾区也是最容易“以为懂了其实没懂”的知识点。先说结论类里有虚函数时对象的内存布局里会多一个虚表指针vptr它指向该类的虚函数表vtbl虚函数表里保存着这个类所有虚函数的地址。调用虚函数时编译器不再直接生成“call 固定地址”的代码而是先通过对象的vptr找到虚函数表再从表里取出函数地址调用。这就是动态绑定的底层原理。为什么析构函数建议声明为virtual因为如果基类指针指向派生类对象delete这个基类指针时只有虚析构才会触发派生类的析构函数否则派生类部分资源没有被释放产生未定义行为。笔试里还有一个高频陷阱构造函数里调用虚函数会发生什么答案是调用的是当前类的版本而不是派生类的覆盖版因为在构造基类部分时派生类还没构造完成虚表指针指向的是当前正在构造的类。静态函数不能是虚函数因为虚函数的调用依赖对象内的vptr而静态函数属于类没有this指针。构造函数也不能是虚函数这个比较好理解对象还没创建没有vptr可用。这些边界问题整理成一张“可以/不可以”的对照表记起来效率高很多。3.2 覆盖、隐藏、重载的边界热词里有“C 覆盖 隐藏”这确实是高频考点很多人分不清。先记住三者的定义重载同一个作用域内函数名相同、参数列表不同与返回值无关。隐藏基类和派生类各有同名函数派生类的名字会隐藏基类所有同名重载不管参数是否相同。覆盖基类函数是虚函数派生类函数签名与基类完全相同返回值是基类返回类型的协变类型这时才叫覆盖。隐藏是最容易理解错的。比如基类有void fun(int)和void fun(double)两个重载派生类只写了void fun()这时候通过派生类对象调用fun(3)编译会报错因为派生类里的fun()把基类两个重载全部隐藏了编译器根本不会去基类里找。想要调用基类的版本必须用using声明或显式基类限定。覆盖是动态多态的基础。如果基类某个函数不是virtual派生类写一个同名同参的函数那不叫覆盖叫隐藏通过基类指针调用时还是调用基类版本。笔试题常给这种代码让判断输出比如基类指针指向派生类对象调一个非虚函数很多人想当然以为是派生类版本结果答错。3.3 静态多态与动态多态多态分两种一个是编译期多态一个是运行期多态。静态多态靠函数重载、运算符重载和模板来实现编译器在编译阶段就确定了调用目标好处是没有运行时开销、可以做内联优化坏处是编译时间变长、代码体积可能膨胀。动态多态靠虚函数和继承来实现运行时通过虚表查找调用目标灵活但多了一次间接跳转而且开O2时虚函数也不适合内联。笔试题里经常给一段代码问这是哪种多态、为什么。判断方法很直接看函数调用在编译时能不能确定。模板实例化、重载选择都是编译期定死的虚函数调用则要看对象的动态类型动态类型由实际指向的对象决定。比如基类指针指向派生类虚函数会走派生类版本这就是动态多态。经常有人把重载也当成多态严格说重载属于静态多态但很多教材里习惯只说“多态”指动态多态答题时看题目的区分方式。3.4 菱形继承与虚继承继承里最让人头疼的是菱形继承。B和C都继承AD再同时继承B和CD里会包含两份A的成员访问时产生二义性。解决办法是虚继承B和C都写成class B : virtual public A这样D里只有一份A的成员。虚继承的底层实现比普通继承复杂涉及虚基类表但笔试一般不会深入到底层布局考到“如何解决菱形继承”知道用虚继承就够了。构造函数调用顺序有个固定规则先构造所有虚基类再按继承顺序构造其他基类然后按声明顺序构造成员对象最后构造派生类自身。析构顺序完全相反。笔试里经常让写初始化列表的顺序或者判断构造函数打印顺序掌握这几条规则就能拿分。还有一个小细节虚基类的构造函数要由最终派生类直接调用如果最终派生类没有显式初始化虚基类编译器会调用虚基类的默认构造即使中间继承类初始化列表里写了也没用。4. 经典算法题与代码题从排序到二分4.1 排序“全家桶”冒泡、快排、归并的手写要点编程题里排序是入门也最常考的方向至少要能手写冒泡排序、快速排序、归并排序还要知道它们各自的复杂度和稳定性。冒泡排序适合教学和热身实际笔试里直接让写冒泡的频率不高但会作为进阶题的基础。冒泡的核心逻辑是两层循环每轮把相邻元素中较大的往后移经过n-1轮后序列有序。优化点在“如果某一轮没有发生交换说明已经有序提前退出”这段代码加不加这个标记体现的代码细节功夫不一样。快速排序是手写概率最高的排序之一。核心是分治选一个基准值把小于基准的放左边大于基准的放右边然后递归处理左右两边。笔试时我会用Lomuto分区或Hoare分区Lomuto好写但常数大Hoare效率高但边界不好把握。要注意快排是不稳定的最坏情况下如果每次基准都选到最大或最小元素复杂度退化到O(n^2)。写的时候建议用中间值或随机元素做基准能在很大程度上避免退化。我贴一段比较常见的手写版本void quickSort(vectorint 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); }归并排序是稳定排序复杂度稳定在O(n log n)但需要额外O(n)空间。笔试里让写归并的机会也不少尤其是涉及链表排序时归并往往是首选因为链表不需要额外空间。C标准库的std::sort底层是内省排序混合了快排、堆排和插入排序日常工程直接用它就行但笔试手写算法还是要掌握原理。使用std::sort记得包含 头文件如果排序自定义类型要提供比较函数或lambda不然编译器报错都不知道错在哪。4.2 二分查找的边界处理二分查找是笔试题里“看着简单写对很难”的典型。核心思路是在有序数组里不断缩小查找范围每次比较中间值和目标值确定目标是在左半区还是右半区。但边界条件写不对很容易死循环或者漏掉边界元素。我在整理这类题时总结了一套固定写法每次都统一用“左闭右闭区间”int binarySearch(vectorint nums, int target) { int left 0, right nums.size() - 1; while (left right) { int mid left (right - left) / 2; if (nums[mid] target) return mid; else if (nums[mid] target) left mid 1; else right mid - 1; } return -1; }几个关键点mid用left (right - left) / 2而不是(left right) / 2防止两个大数相加溢出循环条件是left right还是left right决定了right初值是size() - 1还是size()left mid 1和right mid - 1必须配合否则当left和right相邻时mid可能一直等于left造成死循环。变种题lower_bound也就是找第一个不小于target的位置写法也类似判断条件改成nums[mid] target时left mid 1否则right mid - 1最后返回left。笔试如果时间紧张我建议死记一套写法所有二分题都往这个模板上靠能极大降低出错率。4.3 字符串处理初始化、转数组、流I/O字符串题在笔试里出现频率很高因为它能串起字符数组、指针、内存边界好几个考点。先说说字符串数组初始化。char s[] hello;和char* s hello;有本质区别前者在栈上分配一段可修改的字符数组并且会自动在末尾补\0后者s指向的是只读字符串字面量修改它会导致未定义行为。笔试题经常问这两行代码的区别以及在函数返回值时哪个安全。“字符串转数组”是热词里的常客。把std::string转成char数组可以调用c_str()获得const char*需要可修改的char数组时用strcpy或memcpy拷贝出来如果是按分隔符拆分字符串首选用istringstream配合getline。C流I/O相关题目里getline(cin, str)能读进包含空格的一行而cin str遇到空格就停。这个区别笔试题和实际开发里都很容易踩坑。另外还有个细节如果先cin num再用getline换行符会留在输入缓冲区里导致getline读到空行解决方法是先cin.ignore()。这几个都是热词“c流i/o”里常考的点。字符串题最怕的就是缓冲区溢出。用strcpy前一定要确认目标缓冲区够大否则越界写坏其他数据更安全的做法是用strncpy并手动加\0或者直接用std::string和std::vector 让标准库替你管内存。笔试代码题里只要不是明确要求用C风格字符串我都建议优先用std::string代码简洁且不容易埋雷。4.4 判断质数的常用优化质数判断看着简单优化方式却不少时常被拿来当编程题热身。最朴素的想法是从2试除到n-1判断n是否被整除复杂度O(n)。稍微优化一下只要试到sqrt(n)就行因为如果n有一个大于sqrt(n)的因子必然有一个小于sqrt(n)的因子配对。写成循环时要注意别用i * i n当n接近INT_MAX时i*i会溢出变成负数写成i n / i最安全。再进一步可以跳过偶数只检查奇数和2。这样复杂度能再少一半。更进阶一点是6k±1法大于等于5的质数一定分布在6的倍数两侧也就是6k-1或6k1。因为6k、6k2、6k3、6k4都分别能被2或3整除不可能是质数。实现时先处理2和3然后令步长为6检查i-1和i1即可。笔试一般不会要求到这一步但你能写出来说明对优化有感觉。bool isPrime(int n) { if (n 1) return false; if (n 3) return true; if (n % 2 0 || n % 3 0) return false; for (int i 5; i n / i; i 6) { if (n % i 0 || n % (i 2) 0) return false; } return true; }笔试题里有时候会改成“判断1到n之间有多少个质数”那就不能用单个数逐个判断了n一大就超时这时候要用埃氏筛或欧拉筛。埃氏筛的思想是每找到一个质数就把它的倍数全部标记为合数复杂度O(n log log n)面试中手写也足够。5. 开发环境与编译链接别在这上面栽跟头5.1 VSCode配置C/C环境的思路热词里“vscode配置c/c环境”出现频率不低说明很多人卡在了环境搭建这一步最后连笔试题的本地测试都没法做。我知道很多同学习惯用VS或者CLion但VSCode轻量、免费、跨平台的特性让它成为不少笔试准备者的选择。配置C/C环境核心是三份json文件c_cpp_properties.json负责智能提示和头文件搜索路径tasks.json负责编译launch.json负责调试。我的建议是先用命令行或终端验证编译器可用再配置VSCode。比如Windows上装了MinGW-w64先确认g命令能输出版本然后新建一个helloworld.cpp用g -g helloworld.cpp -o helloworld编译一次确认没问题后再去折腾tasks.json。这样每一步出问题都知道是哪一步的锅而不是堆在一起排查。常见坑有三个编译器路径带空格导致system找不到中文标点引发的stray \343 in program报错头文件路径没写对导致波浪线报错。其中中文标点那类问题肉眼几乎看不出来遇到就先检查代码里的逗号分号是不是全角。5.2 运行库报错Microsoft Visual C Redistributable很多人在安装Python包或某些C依赖库时会看到这么一条报错“error: Microsoft Visual C 14.0 or greater is required. Get it with Microsoft C Build Tools”。这个报错在热词里反复出现确实折磨了不少人。注意这个报错的本质不是缺少运行库而是缺少编译工具链。报错来源通常是pip在安装需要编译C扩展的包时找不到MSVC编译器于是要求你先安装Visual Studio Build Tools。解决办法是到Visual Studio官网下载Build Tools安装时勾选“使用C的桌面开发”工作负载安装完成后重启终端或IDE再重新执行原命令。这个组件体积比较大下载时间可能很长要有心理准备。与之相关的是Visual C Redistributable也就是vc_redist.x64.exe这个只是运行时库用于运行已经编译好的程序不能替代Build Tools。如果程序提示缺少VCRUNTIME140.dll这类文件安装对应版本的Redistributable就能解决x64和x86版本建议都装上因为有些32位程序也需要x86运行库。笔试机试环境要是遇到这种问题先确认目标程序位数别盲目装错版本。5.3 C新特性考察从智能指针到lambdaC11以后的特性在笔试里占比越来越高尤其是智能指针、移动语义和lambda。智能指针前面提过重点在资源所有权unique_ptr不能拷贝只能移动shared_ptr可以拷贝引用计数线程安全但指向的对象的线程安全性要自己负责weak_ptr不增加引用计数专门用于解决shared_ptr循环引用。笔试题常给一个场景问“以下哪个写法正确”或“这段代码会不会内存泄漏”学会画引用关系图很关键。移动语义的核心是右值引用和std::move。为什么要移动因为拷贝大对象开销很大如果右值临时对象马上就要销毁不如直接“偷”它的资源。笔试里经常问vector.push_back(临时对象)时发生了什么以及显式std::move一个左值对象后原对象处于什么状态。这里要记住被move后原对象处于“有效但未指定”的状态不能再随意使用通常只做赋值或析构。lambda表达式考捕获列表。捕获方式分按值捕获[]和按引用捕获[]还可能混合捕获。按引用捕获要注意生命周期陷阱lambda捕获了局部变量的引用如果lambda被存起来并且比局部变量活得长调用时就是悬空引用。笔试题里这种“lambda被放入std::function后生命周期问题”的题目很经典。另外还有mutable修饰、返回类型自动推导都属于新特性里的常规考点。5.4 模板与泛型别只背“模板”两个字模板是C笔试里一个绕不开的坎。函数模板和类模板的基础写法要熟比如template T maxValue(T a, T b)。模板实参推导规则也常考如果传入两个不同类型编译器无法自动推导T需要显式指定模板参数。类模板特化和偏特化则是进阶考点全特化是指定所有模板参数偏特化是只指定一部分参数。笔试不会要求写很复杂的模板元编程但“判断以下哪个是模板特化”“模板这个定义为什么链接报错”这类问题很常见。有一个高频坑很多人踩过模板的声明和定义不能像普通函数一样拆到.h和.cpp文件里如果拆开链接阶段会找不到实现。因为模板在编译时需要根据具体类型实例化而.cpp文件里没有使用场景编译器就不会生成对应代码。解决办法是把模板实现放在头文件里或者采用显式实例化。这个点笔试题里如果考到答不上来就非常可惜。还有一个选项里经常出现的“typename与class在模板参数声明中是否可以互换”答案是基本可以但在声明嵌套依赖类型时只能用typename。6. 常见问题与面试中真实翻车记录6.1 为什么整理C笔试题时会看到一堆“邻居科目”搜索过“C笔试题”的人很可能也会被推荐“Java笔试题”“SQL笔试题”“软件测试笔试题SQL”等内容。这并不是搜索算法抽风而是很多岗位笔试确实是混合卷。比如通用软件开发岗可能同时考C、Java、SQL甚至再夹几道逻辑题和Linux命令。整理的时候要分清楚主次如果你的目标明确是C开发就先把C核心题目解决掉再花少量时间过一遍SQL基础语法比如join、group by、索引原理这些别让边缘科目占用太多时间。另一种情况是投递了大厂的硬件或芯片相关岗位搜出“硬件工程师笔试题”“华为硬件工程师笔试题”“大疆硬件工程师笔试题”就很正常了。我在6.2会专门讲这类岗位的备考差异。还有一个分类是“ros2笔试题”“前端设计笔试题”这些是各自岗位的垂直内容除非你明确要转岗否则不必深入。我整理笔记时习惯建一个“旁路清单”的文件夹把这类邻居科目题目放进去等主科目复习完再决定要不要看避免越翻越焦虑。6.2 硬件与IC岗位的C考察点有些朋友对芯片、嵌入式感兴趣搜过“芯动科技数字ic笔试题”这类内容。这类数字IC设计或验证岗位的笔试里C通常不是大头占比可能只有20%到30%主要考面向对象的基础概念、状态机用代码怎么表达、简单的算法思维比如计数器、序列检测器这种题目可能用类或结构体来描述。真正拉开分数的是Verilog、SystemVerilog、数字逻辑设计、时序约束这些专业内容。如果你目标在这类岗位复习策略不能照搬纯软件C岗的题海核心是把C的“类、结构体、队列、状态机”基础打牢然后集中精力搞硬件语言和数字电路。硬件岗位的C部分偶尔会考到“能不能用一个类实现一个FIFO”“如何用C描述一个高电平有效的信号”这类偏建模的问题熟悉基本语法和常用数据结构就能应对不需要去抠模板元编程。同样的思路也适用于嵌入式岗位区别是嵌入式更看重指针、内存布局、位运算、中断和寄存器操作相关代码这部分反而要多准备。总之先看目标岗位的考察范围再决定C复习到什么深度不要拿着一套软件岗八股硬套所有岗位。6.3 题目刷不完怎么抓主线网上各种“C面试题合集”“C八股文背诵版”动辄几百上千题再加上“C小游戏”“C游戏代码”这种练手项目很容易让人觉得准备不完。实际笔试题目虽然有变化但主线非常稳定内存管理、多态、排序查找、字符串处理、二叉树。我在整理时给自己定的目标是高频主线的题控制在150到200道每道题都吃透而不是膨胀到800题却每道都只看了眼答案。具体抓法可以这样先按主题分类一个主题刷20题左右刷的时候不查答案先自己写写不出来再翻参考。每道题做完在题号旁边写三行备注考了什么知识点、易错点在哪、一句话解题思路。比如“二分查找考边界处理易错是mid取值溢出一句话左闭右闭mid取中左右收缩”。这样一个主题20题刷下来你手里就有了一份很薄的精髓笔记考前翻笔记比重新刷题高效得多。C小游戏之类的代码项目确实能练手感也能提升对语言整体的兴趣但它对应试的直接帮助有限时间不够时优先放弃。6.4 做题顺序、时间分配和复盘的实用技巧到了正式笔试现场时间分配是一门学问。我的通用策略是先把所有题目扫一遍标出会与不会然后按从易到难做选择填空和基础代码题最后留出至少30分钟给编程题。编程题不要上来就写代码先读三遍题把输入输出样例在草稿上演算一次确定边界条件再动手。写的时候可以先写函数签名和主流程注释再逐行填充这样即便中途思路断了也能顺着注释接回来。很多在线笔试系统对输出格式非常严格多一个空格、少一个换行都可能被判错。我的习惯是在本地用自定义样例测试重点测三种数据最小输入如0或1、边界输入如数组为空、最大规模输入测试性能。如果代码编译报错先看提示信息里的行号其次看变量类型匹配再看循环变量有没有拼写错误不要一上来就重写整个函数。复盘的时候把当时没写出来的题目重新手写一遍直到不看答案能独立完成才算是真正掌握。这个习惯坚持一两个月对代码速度的提升非常明显。最后补一句我自己的做题习惯我会把每道错题都整理成“题干一句话 正确答案 如果掉坑会输在哪一环节”的三行笔记而不是一长段摘抄。这样到笔试前一天扫笔记只需要20分钟。C的知识点再多考来考去其实还是那几个核心对象生命周期、内存、多态、算法边界条件。把这些主线抓住笔试题看着再花哨解法也不会跑出这个圈。
返回列表