网易2020校招C开发笔试考点复盘:从指针到链表的备考指南
前阵子辅导一个准备秋招的学弟又翻出了网易2020校招C开发工程师正式批的笔试资料。说实话那套题放在今天看难度不算夸张但筛人能力很猛——选择题考察的C语言细节点非常密集编程题虽然不偏却总有人因为基本功不牢在简单题上卡住。我结合自己当年参加校招和后来协助面试的经验把这套笔试涉及的考点、常见坑和备考方法完整梳理一遍希望能帮准备投C开发岗的同学少走弯路。1. 网易2020校招C开发的笔试题型与备考主线1.1 笔试的整体节奏与题型构成网易的校招笔试通常在牛客网上统一进行C开发工程师岗位的笔试题型基本是选择题加编程题的组合。选择题大概20到30道覆盖C语言语法细节、数据结构、操作系统、计算机网络、Linux基础等编程题通常是2到3道核心以模拟题、字符串处理、链表和基础算法为主。这里要特别说明虽然是C开发岗但笔试中的操作系统和网络题不会太深重点还是C语言本身以及用C语言解决算法的能力。2020年正式批的笔试整体节奏偏紧选择题需要快速判断编程题则考察代码的完整性和边界处理。很多人以为C开发岗会侧重嵌入式或底层知识实际上网易的笔试更看重基础通用能力操作系统和网络只是点缀C语言的基本功才是真正拉开差距的地方。1.2 为什么说C基础不牢选择题直接崩网易笔试的选择题有一个鲜明特点它经常用一段很短的代码考察你对C语言的熟练程度。例如给出一段涉及指针运算、运算符优先级、类型转换、static关键字、宏定义的代码问你输出是什么。这类题就是典型的看着简单答案很容易选错。拿运算符优先级举例*p 到底是 (*p) 还是 *(p)很多写了好几年C的同学都可能一时卡壳。笔试考的就是这种细节——如果你平时只是能用C写点功能但没认真抠过语言规范选择题很难拿高分。搜索引擎里 c语言运算符优先级、c语言指针、c语言字符串函数 这类关键词常年是C语言学习者的高频搜索对象说明这些确实是绝大多数人的薄弱环节。1.3 备考主线的建议如果时间有限我建议按这样的优先级准备夯实C语言语法细节指针、数组、字符串、结构体、位运算、文件操作掌握用C语言实现常见数据结构和算法链表、栈、队列、排序、二分、字符串处理熟悉在线笔试环境牛客网、力扣的C语言提交方式尤其是输入输出处理这里面最容易被忽视的是第三条。很多人在自己的IDE里写C代码写得飞起一上牛客就卡在scanf和gets的换行符处理上实在可惜。后面我会单独讲在线笔试的输入输出技巧。2. 指针与内存管理选择题失分重灾区怎么补2.1 指针与数组最常考也最容易被绕晕的关系数组名在大多数表达式中会退化为指向首元素的指针但有两个例外sizeof(数组名) 和 数组名。笔试选择题非常喜欢拿这两个例外出题。int a[5] {1, 2, 3, 4, 5}; printf(%d\n, sizeof(a)); // 20整个数组的大小 printf(%d\n, sizeof(a 0)); // 8a0已经退化为指针 printf(%d\n, sizeof(a)); // 8a是int(*)[5]类型指针 printf(%d\n, sizeof(a[0])); // 8指向具体元素的指针这道题能说明很多问题。很多同学记住了 sizeof(a) 是20但容易忽略 sizeof(a 0) 其实是指针的大小因为 a 0 已经发生了数组到指针的退化。这类代码如果出现在笔试选择题里基本就是送分还是送命的区别。从这里出发还能延伸出 a[2] 和 *(a2) 等价、a 1 会跳过整个数组20字节等考点。2.2 指针运算的边界p 1 到底前进多少个字节取决于 p 的基类型。int* 加1前进4个字节char* 加1前进1个字节int()[5] 加1前进20个字节。结合p、(p1)、p 这类写法选择题能变出很多花样。举个例子很多同学容易混淆 *p 和 (*p) 的语义。注意后缀运算符优先级高于解引用*p 实际是 *(p)即先取 p 当前指向的值然后 p 自增指向下一个位置而 (*p) 是让 p 指向的值自增。这种区别在遍历数组的代码里非常关键。另外一个高频考点是二级指针。函数里要修改外部指针变量的值必须传二级指针。比如链表的头插法如果你希望插入后头指针改变就必须传 ListNode** head否则函数内部的修改在外部不生效。有些同学总爱写 ListNode* head 然后企图在函数里修改 head这是不理解C语言参数传递的典型表现。2.3 malloc/free 与内存泄漏网易笔试对动态内存的考察集中在几个点malloc 的返回类型是 void*在C语言中可以不强制转换但C必须转换malloc/free 必须配对使用释放后指针要置NULL内存泄漏在函数里 malloc 之后如果提前 return没有 free 就会泄漏野指针free 之后没有再置 NULL后续可能被误用下面这段代码是一个经典的反面教材char* get_string() { char* p (char*)malloc(10); strcpy(p, hello); return p; // 调用方负责free但很容易忘了 } int main() { char* s get_string(); printf(%s\n, s); // free(s); 如果忘了这一句就是内存泄漏 return 0; }笔试里可能会问你这段代码有没有问题答案是如果调用方没有释放就有内存泄漏。这在长期运行的服务端程序里是致命的所以开发岗笔试对内存管理格外重视。2.4 内存错误排查思路笔试虽然不会让你现场调试内存错误但选择题里会给出一个程序运行崩溃的场景让你猜原因。常见的有越界访问数组下标越界空指针解引用访问了NULL指针指向的内存重复释放同一块内存 free 了两次栈溢出递归没有终止条件或局部数组过大排查思路一般是先看崩溃地址如果是0x0附近基本都是空指针如果是随机地址大概率是野指针如果加了 -fsanitizeaddress 重新编译可以直接定位越界位置。虽然笔试不考编译参数但这个思路对实际开发帮助很大。我建议同学们在本地验证内存问题时养成编译时加 -Wall -fsanitizeaddress 的习惯能省下大量排查时间。3. 字符串处理、结构体与链表小题大题共同的出题热点3.1 字符串函数的隐藏细节strlen 统计的是到第一个 \0 之前的字符个数不包含 \0 本身。strcpy 会把源字符串的 \0 一起拷过去。strcmp 比较的是字符的ASCII码差值不是字符串长度。这些基础点如果只背结论遇到变体题很容易翻车。比如下面这个经典选择题char s[10] hello; printf(%d\n, strlen(s)); // 5 printf(%d\n, sizeof(s)); // 10strlen(s) 和 sizeof(s) 的区别几乎是C语言笔试必考。strlen 在运行时统计字符个数sizeof 在编译期确定类型占用字节数。一旦理解了这一点很多变体题都能迎刃而解。另外还要注意 strcpy 的危险性它不检查目标缓冲区大小很容易造成缓冲区溢出笔试有时候会问下面哪个函数可以避免缓冲区溢出答案是 strncpy 或 snprintf。3.2 字符串逆序的多种实现字符串逆序这个题目在各大笔试平台的C语言题库里出现频率极高。它看似简单但很能考察代码风格和边界处理能力。基础版本是双指针交换void reverse(char* s, int left, int right) { while (left right) { char tmp s[left]; s[left] s[right]; s[right] tmp; left; right--; } }如果题目要求逆序整个字符串直接调用 reverse(s, 0, strlen(s)-1)。如果要求逆序每个单词但保持单词顺序就是先整体逆序再对每个单词单独逆序。这个变体在笔试中更常见因为它更贴近工程里的实际场景。还有更进阶的版本要求原地逆序且不能使用额外空间依然是双指针思路只是指针移动的判断要更仔细。3.3 字符数组与字符串指针的区分char str[] hello 和 char* str hello 在笔试中经常被拿来对比。前者是栈上的数组可以修改内容后者指向字符串字面量位于只读区修改会崩溃。很多同学写过 char* p abc; p[0] x; 然后程序莫名其妙crash其实就是这个原因。选择题里还可能这样问sizeof 分别输出多少。char str[] hello 的 sizeof 是6包括结尾的\0而 char* str hello 的 sizeof 是指针大小8或4。这一点和上面 strlen 的对比结合起来就是一道完整的选择题。3.4 结构体对齐与内存布局结构体对齐是选择题的高频考点。笔试常见问法下面这个结构体占多少字节struct Node { char c; // 1 int i; // 4 char d; // 1 };按默认对齐规则char c 占1字节为了对齐 int i需要填充3字节所以 c 后面有3个paddingi 占4字节d 占1字节后整个结构体大小必须是最大对齐数4的倍数所以末尾还要补3字节。总共 1 3 4 1 3 12 字节。如果调整成员顺序把 int 放在前面char 放在一起可以压缩到 8 字节。这个考点对于开发工程师来说不只是应付笔试实际在写网络协议、文件格式解析时结构体内存布局直接决定序列化结果是否正确错一位就是整个包解析失败。3.5 链表题目的C语言实现要点链表相关的题目几乎每次网易笔试的编程题都会涉及。反转、合并、删除倒数第N个节点、判断是否有环都是常客。这里分享一个链表反转的迭代实现struct ListNode* reverseList(struct ListNode* head) { struct ListNode* prev NULL; struct ListNode* curr head; while (curr) { struct ListNode* next curr-next; curr-next prev; prev curr; curr next; } return prev; }关键点是在改变 curr-next 之前必须先把 next 保存下来否则链表就断了。这算是链表题里最基本也最容易被忽略的细节。另外要注意循环终止的条件是 curr 为空此时 prev 正好指向原链表的尾节点也就是反转后的新头节点。如果题目要求递归写法思路一样只是把迭代改成递归但要注意递归深度可能在大链表上溢出。4. 经典算法在C语言笔试中的考查方式与实现细节4.1 排序算法不只要会写还要知道边界排序算法在C语言笔试题里很常见尤其是冒泡排序。冒泡排序的写法本身不难但要保证无bug需要记住内层循环的边界条件void bubble_sort(int arr[], int n) { for (int i 0; i n - 1; i) { for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; } } } }笔试选择题有时会问某轮冒泡之后数组的状态这就要求你手动模拟一遍排序过程。平时练习时我建议用纸笔模拟几次而不是只会在电脑上跑通。快速排序和归并排序也偶尔会出现在编程题中尤其是排序后需要保持某种稳定性的场景。C语言标准库的 qsort 函数在笔试里可以放心用但要注意比较函数的写法返回值的正负要符合 qsort 的预期。4.2 二分查找的边界条件二分查找在选择题和编程题中都可能出现。最常见的坑是循环条件用 left right 还是 left right以及 mid 的更新方式。一个稳妥的写法是int binary_search(int arr[], int n, int target) { int left 0, right n - 1; while (left right) { int mid left (right - left) / 2; if (arr[mid] target) return mid; else if (arr[mid] target) left mid 1; else right mid - 1; } return -1; }注意 mid 的计算用 left (right - left) / 2 而不是 (left right) / 2因为后者在极端情况下可能溢出。这个细节在面试时经常被追问。笔试选择题还可能出现数组中有重复元素时怎么找到第一个或最后一个等于target的位置这需要把等于的情况和收缩方向结合起来考虑多写几道类似题目就能掌握套路。4.3 模拟题日期计算与流程模拟热词里输入一个日期的年、月、日计算并输出这天是该年的第几天这种题目非常典型。它看起来简单但涉及闰年判断、月份天数表、循环累加能考察代码的完整性。int is_leap(int year) { return (year % 4 0 year % 100 ! 0) || (year % 400 0); } int day_of_year(int year, int month, int day) { int days[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (is_leap(year)) days[1] 29; int sum 0; for (int i 0; i month - 1; i) { sum days[i]; } return sum day; }这类模拟题考察的是能不能把现实规则转换成无bug的代码在笔试里的性价比很高因为思路简单只要细心就能拿分。类似的还有进制转换、括号匹配、大数加法等。做这类题的关键是先把变量定义清楚再动手写逻辑不要一上来就写代码容易漏边界。4.4 运算符优先级与位运算选择题中C语言运算符优先级几乎是必考。记住几个容易混淆的后缀 /-- 的优先级高于前缀 /--一元运算符! ~ -- * 高于算术运算符移位运算符的优先级低于算术运算符但高于关系运算符位与 的优先级低于等于运算符逻辑或 || 的优先级最低位运算在嵌入式开发方向和C开发岗笔试中都经常出现。指定位置的置位、清位、翻转可以用下面这套写法// 把第n位置1 x | (1u n); // 把第n位清0 x ~(1u n); // 判断第n位 if (x (1u n)) {}热词里出现svpwm的c语言程序热敏电阻制作温度传感器的c语言说明很多考C开发岗的同学其实有着嵌入式背景位运算对他们来说是日常操作但对纯软件方向的同学来说还是要专门复习。位运算还有一种常见题型是统计二进制中1的个数用 n (n - 1) 可以高效实现笔试选择题偶尔会考这个技巧。5. 编程题实战从读题到通过用例的完整流程5.1 在线笔试的输入输出处理网易的笔试用的是牛客网OJ和力扣不一样的是牛客网需要你自己处理输入输出。很多C语言基础不错的同学第一个大坑就是不会读输入。常见的输入形式有多组输入读取到EOF结束第一行给一个整数n表示数据个数给一行字符串可能包含空格也可能不包含处理方式如下// 多组输入每组两个整数 int a, b; while (scanf(%d%d, a, b) ! EOF) { // 处理每一组 } // 读取包含空格的整行字符串 char line[1024]; fgets(line, sizeof(line), stdin); line[strcspn(line, \n)] \0; // 去掉末尾换行符scanf 的一个大坑是它读取 %d 后会留下换行符导致后续 fgets 读到空行。解决办法是读取后调用 getchar() 消费掉换行或者统一用 fgets 读行再 sscanf 解析。笔试里因为输入格式没处理好导致AC不了非常冤枉。我见过太多人代码逻辑全对就是输入读取出了问题白白丢分。5.2 一个完整编程题的思考路径以字符串逆序这个经典题为例完整的思考路径应该是先确认输入方式一行字符串可能包含空格确定逆序范围是整行逆序还是按单词逆序选择算法双指针交换法时间复杂度O(n)空间复杂度O(1)处理边界空字符串、只有一个字符、末尾换行符如果看到题目第一反应是再开一个数组倒着拷贝也能AC但不是最优。笔试最后一两道题往往有时间复杂度要求暴力解可能只能过部分用例所以至少要掌握双指针和哈希表这两种优化手段。还有一种常见题型是链表相关的编程题比如判断链表是否有环。最简单的方法是快慢指针一个每次走两步一个每次走一步如果相遇说明有环。这个思路代码量不大但原理很巧妙建议同学们把链表的常见题型都提前写过。5.3 交卷前的自查清单编程题提交前我习惯做几件事检查数组是否开得足够大有没有越界风险检查 while 循环是否会死循环尤其是链表题检查返回类型和printf格式符号是否匹配%d、%ld、%lld检查是否有内存泄漏虽然OJ不检测但面试官看代码时会介意用几组特殊用例自测空串、全相同字符、最大n、最小n这些习惯不是笔试前临时抱佛脚能养成的平时刷题时就要刻意练习。我每次提交前都会花一分钟快速扫一遍基本能避免大部分低级错误。6. 基于2020笔试复盘说说我的备考建议6.1 刷题节奏怎么安排如果你离笔试还有1到2个月我建议这样安排前2周专攻C语言基础指针、数组、字符串、结构体、内存管理配合选择题练习中间2周专攻数据结构和算法链表、栈、队列、排序、二分、字符串处理最后1周集中刷牛客网真题熟悉OJ的输入输出风格不要一上来就刷难题校招笔试的重心从来不是难题而是基础题的准确率。网易2020这套卷子也是这样难题没有多少但基础题的坑密布认真复习过的人能拿高分靠裸考的人会在很多看起来简单的题上反复翻车。选择题的正确率决定了你能不能进面试而编程题的正答率决定了你在排序里的位置两者都不能偏废。6.2 简历之外的软实力代码风格笔试编程题虽然只看用例通过率但代码风格会影响后续面试官的印象。如果在笔试代码里体现了良好的编码习惯面试时被问起也会有加分。写代码时注意变量命名清晰不要用 a、b、c 这种毫无意义的名字函数边界处理完整空指针、空字符串要有guard关键逻辑写一行注释让面试官知道你的思路我之前看过一些笔试代码逻辑是对的但变量名是 x、y、z 的缩写函数里没有什么注释面试官很难快速读懂。要知道笔试代码是会被面试官翻出来的代码风格本身就是综合能力的一部分。6.3 笔试前的临门一脚到了笔试前一周不建议再啃新知识了重点是巩固和热身。我个人的做法是每天花15分钟手写两个经典函数链表反转和字符串逆序。不是背而是闭着眼睛写直到形成肌肉记忆。这两个小函数在网易的校招笔试里出现的概率真的很高提前准备好了拿到题就能直接进入得分的节奏。另外笔试前一天晚上把牛客网的答题环境熟悉一遍至少知道代码怎么提交、编译报错怎么查看、自测用例怎么填。很多人第一次用牛客网答题连输入样例怎么粘贴都不熟练白白浪费了宝贵的答题时间。这种环境上的熟练度和代码能力一样重要。我在实际辅导过程中发现最容易在笔试里翻车的往往是两类人一类是基础不牢的半壶水选手另一类是基础扎实但输在输入输出或不熟悉OJ环境的实战小白。前者的解法是多啃基础后者的解法是多刷真题熟悉流程。希望这篇梳理能帮你找到自己对应的短板有针对性地补上。

相关新闻

最新新闻

日新闻

周新闻

月新闻