
看到“网易2018实习生招聘笔试题-C 开发实习生”这个标题很多准备校招的朋友估计心里会咯噔一下。网易这套C开发岗的笔试题虽然已经是好几年前的了但在国内大厂校招的C语言笔试题里直到今天都还算得上是一份很有参考价值的“照妖镜”专门照出你C语言基本功到底扎不扎实。我当时参加完笔试最大的感受是题不算偏但每个考点都卡在“你以为你会一写就废”的位置上。这篇文章不聊公司就纯粹从题目背后的技术点出发把C开发实习生笔试题拆开揉碎给准备校招、实习或者想检验自己C语言水平的同学一个系统的复习框架和实操参考。1. 网易2018C开发实习生笔试到底在考什么1.1 考点范围和命题逻辑先说结论这份笔试题的核心命题思路不是要考你多高深的算法而是要筛出“能真正用C语言干活的人”。根据当时网上大量参与者的回忆和岗位描述主要考察范围集中在C语言语法基础、指针与内存管理、字符串处理、结构体与联合体、文件操作、预处理指令以及数据结构链表、栈、队列、二叉树、图和基础算法排序、查找、递归。部分题目还会带上操作系统和Linux指令的基础题因为C开发实习生往往要接触后台服务、中间件或者底层工具链不懂系统层面的东西不行。为什么这样出题道理很简单。C语言和Java、Python不一样它没有任何“安全网”。数组越界不报错内存泄漏不提示野指针说崩就崩。一个能写生产级C代码的人必须对内存地址、指针类型、生命周期这些概念形成肌肉记忆。所以笔试题里最密集的考点永远是指针和内存。你可以不会做动态规划但你绝对不能解释不清malloc和free是如何配对的。这个逻辑决定了后续所有题型的分布。1.2 题型结构、难度分布与参考价值按照公开的回忆信息整理这套笔试题大致包含三类选择题、程序填充/改错题、编程题。时间一般安排在90到120分钟题量不算小需要比较强的节奏感。选择题大概20道左右覆盖概念辨析和易错点编程题一般2到3道有时候会要求你补充完整代码有时候是给定场景让你从头写。难度上比普通学校的C语言期末考试要难但比ACM竞赛简单得多属于“扎实复习过就能做裸考一定挂”的区间。这里我要多说一句网易2018这套题真正值钱的地方不是原题本身而是它覆盖的知识面非常典型。你完全可以把这份卷子当成一张C语言自测清单。我当时复习完后列了一个自查表能不能手写字符串逆序能不能十分钟内写出链表反转知不知道sizeof和strlen的区别能不能说出static修饰全局变量和局部变量时分别是什么作用如果这些都能答清楚那你面对大部分大厂C/C实习生的笔试至少不会心虚。2. 把这些考点学透笔试才算真正过关2.1 指针、数组与内存管理C语言的重中之重网易这套题里指针相关题目占比相当高。如果你现在还在靠死记硬背应付指针那笔试现场会非常痛苦。核心要理解这几组概念sizeof和strlen的区别、数组名和指针的关系、指针数组和数组指针的区别、函数指针的用法、以及malloc与free的动态内存管理。先说sizeof和strlen这两个东西是笔试选择题的常客。sizeof是运算符在编译期就能算出结果它计算的是“占用内存的大小”strlen是函数在运行期逐个字符数到\0才停止它算的是“字符串的实际长度”。举个例子char *p hello;那么sizeof(p)在64位系统下一般是8指针本身占8字节而strlen(p)是5。这个区别不清楚的话很多选择题会连环翻车。再说数组和指针。int a[10]; int *p a;以后p[i]和*(pi)等价这是基础。但数组名a不是指针变量它是首元素的地址常量不能执行a。笔试中常见的陷阱是sizeof(a)是整个数组的大小40而sizeof(p)是指针大小8。另外还有多维数组的指针操作比如int a[3][4]; int (*p)[4] a;这里p是指向“包含4个int的数组”的指针p1移动16个字节4个int不是4个字节这种题不写代码踩两遍很容易忘。内存管理方面核心是三点。第一malloc要和free配对申请的内存一定要记得释放。第二释放后的指针要立即置为NULL不然就成了“悬垂指针”下次不小心解引用就是未定义行为。第三free只能释放malloc或calloc等动态分配的内存绝不能用来释放栈上的数组或字符串字面量。很多编程题里你以为自己写对了一free就直接Segmentation fault原因就是对这块理解不透。2.2 字符串处理与库函数细节C语言没有内置的字符串类型所有字符串本质都是“以\0结尾的字符数组”。这个特性决定了字符串题目是笔试的大热门。网易比较喜欢考两类一类是要求自己实现字符串函数另一类是给出一个字符串处理的场景让你找出代码里的内存越界问题。你需要掌握的库函数包括strlen、strcpy、strncpy、strcmp、strcat、sprintf、snprintf。但要记住笔试不是考你会不会调用而是考你知不知道它们背后的坑。比如strcpy不会检查目标缓冲区是否够大一旦源字符串比目标数组长就会越界写入轻则覆盖其他变量重则直接崩溃。安全的写法应该用strncpy或者snprintf并确保在结尾手动加\0。另一个常见坑是char *s hello;和char s[] hello;的区别前者是字符串字面量存在只读区任何修改都会导致运行时错误后者是栈上的数组可以被修改。如果你在编程题里写了void reverse(char *s)然后直接传入了字符串字面量那程序一运行就会崩。字符串逆序是这里面最典型的练习后面我会专门给代码。这里想强调一个容易被忽视的点题目里说“逆序输出”和“原地反转”是两码事。逆序输出只需要倒着遍历一遍不修改原字符串原地反转则需要交换首尾字符必须保证传入的是可写内存。先看清楚题目要求再动手能省下很多调试时间。2.3 数据结构与算法从链表到DijkstraC开发岗笔试题里的数据结构通常不会让你去调现成的库而是让你自己实现。这意味着你必须掌握最基本的链表操作创建、插入、删除、遍历、反转、合并两个有序链表、找倒数第K个节点。链表题的复杂度不高但对指针操作的要求非常细致尤其要注意头节点的特殊情况。我当年在链表反转上栽过一次写完代码自己觉得没问题运行起来却死循环原因就是反转时没有先保存cur-next。这种错误在脑子里过一百遍都发现不了非得上机跑一遍才有感觉。栈和队列的基础操作也要会尤其是用数组模拟栈、用两个栈实现队列这类经典题属于校招笔试的“万金油”。树这一块二叉树的递归前中后序遍历要能随手写出来非递归版本至少理解原理能够说明用栈模拟的过程。图论方面网易这类大厂有时候会考到最短路径其中Dijkstra算法是高频题。实习生笔试对Dijkstra的要求通常不高能写出朴素的O(V^2)版本并解释清楚“为什么每次选距离最小的未访问节点”就够用。核心是用一个数组记录当前最短距离每次从未访问集合里挑出距离最小的点然后用它去松弛相邻节点。如果时间充裕可以再优化成小顶堆实现属于锦上添花。排序算法里冒泡排序、选择排序、插入排序、快速排序都是重点。不要只背时间复杂度要能写出正确代码最好还能分析出什么时候快排会退化。二分查找也很常考重点在于边界条件while (left right)还是while (left right)mid怎么取找到目标后left和right怎么移动。边界条件错一次笔试里基本就废了。2.4 文件操作、预处理与Linux基础文件操作是C语言里相对独立的一块笔试一般不会出太复杂的题但基础API必须会用。fopen的打开模式fread和fwrite的读写逻辑fgets和fprintf的区别fclose的释放这些都属于“背下来就能得分”的题。注意文本模式和二进制模式的区别Windows下fopen(file, rt)和rb对换行的处理不一样读二进制文件的时候如果忘了带b数据可能被意外转换。这点在Linux下虽然没影响但网易笔试用的在线系统通常是Linux所以不用太担心理解了原理就好。预处理部分重点掌握#define宏定义的参数括号问题。经典例子是#define SQUARE(x) x * x传入SQUARE(a 1)会被展开成a 1 * a 1结果完全不对。正确的写法是#define SQUARE(x) ((x) * (x))。这种细节属于选择题高发区平时不注意考场上很容易想当然。还要理解#ifndef头文件守卫以及static和extern的区别。static修饰局部变量时变量生命周期延长到程序结束但作用域不变修饰全局变量时限制只能在当前文件使用修饰函数时也一样函数仅在本文件可见。这些如果不理解靠背很容易混。Linux基础命令不要忽略。C开发实习生入职后基本都是Linux环境笔试可能通过几道选择题或简答题来考察ls、ps、grep、find、top、netstat以及gcc常用编译参数-Wall -g -o。不用背语法但至少知道它们是干嘛的。另外gcc的编译过程预处理、编译、汇编、链接这四个阶段的产物是什么也经常考。预处理生成.i文件编译生成.s汇编汇编生成.o目标文件链接生成可执行文件这条流水线建议背熟。3. 典型编程题实战给你能直接跑通的C代码3.1 字符串逆序输出三种写法与面试官视角字符串逆序几乎是笔试和面试里出现频率最高的题没有之一。别小看它里面能拆出很多层。第一种方式是“倒着打印”不修改原字符串代码如下#include stdio.h #include string.h void print_reverse(const char *s) { if (s NULL) { return; } int len strlen(s); for (int i len - 1; i 0; --i) { putchar(s[i]); } putchar(\n); }这里有个小坑如果len为0i初始值是-1循环条件i 0为假不会进入循环逻辑没问题。但如果把i声明成size_t无符号数i--在i为0后还会继续变成SIZE_MAX造成死循环所以用带符号整数在这个函数里更安全。第二种方式是“原地反转”。注意传入的字符串必须存储在可修改的内存里比如字符数组。如果写成char *s hello;然后传入函数会在运行时崩溃因为字符串字面量在只读段。#include stdio.h #include string.h void reverse_in_place(char *s) { if (s NULL) { return; } int len strlen(s); int i 0; int j len - 1; while (i j) { char tmp s[i]; s[i] s[j]; s[j] tmp; i; --j; } }面试官喜欢的点在于你用双指针从两端向中间遍历时间复杂度O(n)空间复杂度O(1)没有额外开数组思路清晰。如果递归反转虽然代码很简洁但会被追问“递归深度会不会导致栈溢出”实际项目里一般不会用递归做这种操作。第三种是“自己实现strlen加反转”这道题的重点已经不是完成功能而是展示你对边界条件的敏感。写完代码后可以主动补充一句如果s为NULL函数应该怎么处理如果字符串很长用双指针是否比用临时数组更省内存。这种细节才是网易这类公司真正想从笔试题里看到的。3.2 冒泡排序优化手写排序的正确姿势排序题在笔试里属于“新手觉得简单老手不敢大意”的题。网易如果让你手写排序大概率不是单纯考你排序本身而是看你的代码习惯和边界处理。冒泡排序最基础的版本直接两个嵌套循环就写出来了但它有个问题如果数组在某一轮已经有序继续比较纯属浪费。优化方法就是增加一个swapped标志每轮结束后如果发现没有发生交换直接退出。#include stdbool.h void bubble_sort(int *arr, int n) { if (arr NULL || n 0) { return; } 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]) { int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; swapped true; } } if (!swapped) { break; } } }为什么内层循环的边界是n - 1 - i因为每一轮都会把当前未排序部分的最大值“冒泡”到最后面已经排好的尾部元素不需要再参与比较所以每轮少比较一个。如果写成n - 1功能也正确但会多做一些无用功。笔试时写出优化版至少能说明你对算法是理解了的而不是背代码。如果想在排序题上再拉开一点差距建议多准备一个快速排序。快速排序写起来要处理递归基、分区下标容易出错但它考的概率也很高。你可以这样说在不要求稳定的情况下快排平均O(n log n)原地排序空间占用小所以实际使用更多。笔试里如果时间紧张正确实现冒泡排序就已经能拿到大部分分数但千万不要把排序写成死循环。3.3 链表反转与改错题笔试中的“隐藏高分点”链表反转是我个人强烈建议每个人都应该能手写出来的题。它比字符串反转更锻炼指针操作而且非常容易在改错题里埋坑。迭代版本的核心是从头到尾遍历每遇到一个节点就把当前节点的next指针指向前驱节点同时保存好下一个节点不然链表就断了。struct Node { int val; struct Node *next; }; struct Node *reverse_list(struct Node *head) { struct Node *prev NULL; struct Node *cur head; while (cur ! NULL) { struct Node *next cur-next; cur-next prev; prev cur; cur next; } return prev; }关键点就在struct Node *next cur-next;这一行必须在修改cur-next之前保存。我第一次手写的时候就是忘了保存结果cur走了两步就回到自己头上代码直接死循环。调整好这个以后反转本身就不难了。如果链表题目要求递归反转你还需要能解释递归的基线条件和返回值变化但迭代版本足以应付绝大多数笔试。网易笔试题里还有一类程序改错题专门考你对C语言陷阱的敏感度。我遇到过的经典错误大概有三类第一strcpy拷贝到没有足够空间的缓冲第二free之后没有把指针置空然后再次free或访问第三函数返回了局部变量的地址比如int *f() { int a 1; return a; }函数结束后栈空间释放返回的地址成了悬垂指针。做改错题的时候建议养成一个习惯凡是出现指针先问自己三个问题——它有没有初始化它指向的内存还在不在它最终有没有被正确释放这三问一过大部分坑都能看出来。4. 笔试现场实战环境、时间与避坑指南4.1 开发环境配置别让工具问题拖后腿笔试一般都是在牛客、赛码这种在线平台上进行写代码的时候不需要你自己本地的IDE但平时练习时如果连C语言环境都没配好考前心态会先崩一半。很多同学用VSCode写C语言最常遇到的困惑是代码写了运行按钮不可点或者报gcc不是内部或外部命令。这通常是因为本机没有安装编译器或者没有把编译器的路径加入系统的环境变量。我建议基本配置是这样的Windows环境下安装MinGW-w64安装完成后把bin目录的完整路径加到系统环境变量Path里然后在命令行输入gcc --version验证是否成功。接着在VSCode里安装C/C扩展配置好tasks.json和launch.json初学者可以直接用官方模板等熟悉了再手动调整编译参数。另外有些同学会在运行某些脚本时遇到类似“无法加载文件 ... .ps1因为在此系统上禁止运行脚本”的提示这个其实是PowerShell的执行策略限制跟C编译器无关但如果你在用npm之类的工具时会更容易碰到。遇到这种问题不要慌先看清楚是不是执行策略导致的针对性解决就好。调试C代码最推荐的方法是先用命令行编译运行看得清报错信息然后再回到编辑器里改。当然笔试现场用的编译环境和本地可能有差距比如编译器版本不同、标准库实现不同、平台大小端不同。所以平时练习尽量把-Wall警告打开把所有 warning 都当 error 对待。很多问题在本地被自动忽略了到了线上平台就会现出原形。4.2 时间分配与做题策略网易2018这场笔试的时间分配我个人建议是选择题控制在40分钟以内编程题留出至少40分钟最后10分钟用来检查输出格式和边界条件。选择题里如果卡了超过3分钟先标记跳过去不要在单个概念题上死磕。很多选择题的选项看似模棱两可其实考的就是你对“未定义行为”的理解。比如“int a 1; printf(%d %d, a, a);输出什么”如果出这种题正确答案往往是“未定义具体看编译器实现”而不是某个确定的数字。编程题一定要先读清楚题目要求再动手。看清楚是“输出结果”还是“实现函数”是“标准输入输出”还是“从文件读取”。在线笔试系统对格式非常敏感多一个空格、少一个换行都可能导致判题失败。我建议在本地练习时就用牛客或者类似平台的“ACM模式”多训练学会自己处理输入输出而不是只在IDE里写死数据测。做题顺序上先做最有把握的编程题把保底分拿到手再回头处理纠结的选择题。因为编程题往往分值高而且一旦提交后发现错误还能改选择题交卷后就没有机会了。有些编程题是多个测试用例输入的读完题目后要立刻想到“这段代码要放进while(scanf(%d, n) ! EOF)循环里吗”这种细节非常影响得分。4.3 常见编译运行报错排查速查表我把实际练习里高频踩到的报错整理成了一张表建议你在笔试前过一遍。这些报错本身也是网易这类公司喜欢在选择题里当选项出的会看就不吃亏。报错信息常见原因排查方法Segmentation fault指针未初始化、越界访问、空指针解引用用printf在关键位置打点定位崩溃前最后一条输出Undefined reference toxxx函数声明了但没定义或链接时缺库检查文件是否完整函数名是否拼写一致fatal error: xxx.h: No such file头文件路径不对确认头文件名和编译时-I路径implicit declaration of function忘记包含头文件加上#include string.h等对应头文件Stack overflow递归没有出口或者局部数组太大检查递归基把大数组改成全局或堆分配double free or corruption同一块内存被释放两次释放后立刻置NULL避免重复释放这中间我最有感触的是“打点法”。笔试现场没有GDB肉眼又看不出问题用printf一行一行定位是最笨但最有效的办法。不要觉得打印日志会影响代码整洁先找到崩溃原因删掉调试输出再提交才是正路。5. 准备网易C开发笔试时我最后悔没做好三件事5.1 只刷题不动手笔试一写就崩刷题软件和视频课看多了会产生一种“我都懂”的错觉。其实C语言是非常依赖手感的东西指针运算、内存分配、链表操作只有动手写完一遍你的大脑才会真正记录下这些细节。我备考时一开始光看知识点总结心里觉得“很简单”结果第一次在线模拟连malloc后的空指针判断都忘了写编译过了运行的时候直接崩。后来强制自己每天手写3个小程序坚持一周后写链表反转基本不用试错一次能过。动手写出来的代码才是自己的眼睛看会的都不算。5.2 不重视内存细节debug时间比写题时间还长我见过不少同学编程题思路是对的但调了二十分钟才发现问题出在free了栈上变量或者strcpy越界。网易这种公司尤其看重内存安全因为他们做的业务一旦内存崩了后果比普通Web应用严重得多。所以平时练习时就要有意识地用valgrind或ASanAddressSanitizer检查内存泄漏和越界。笔试没机会用这些工具但你在平时养成了检查内存的习惯写出来的代码自然会规避掉这些坑。我自己在备考后期给自己定了一条规矩每个动态分配的程序必须写对应的释放逻辑并反复确认释放顺序。这个习惯帮我省了很多debug时间。5.3 没有形成自己的代码模板最后一个建议可能最实用把高频题整理成自己的代码模板。我说的模板不是死记硬背而是针对固定结构形成肌肉记忆。比如链表节点的定义、反转链表的迭代写法、二分查找的边界模板、Dijkstra的邻接矩阵版本、快排的分区逻辑这些内容每次笔试前过一遍上考场等于带着一份“编译在脑子里”的代码库。你不需要一字不差地写出来但只要框架在填细节就会快很多。网易2018这套题给我最大的收获不是拿到什么分数而是让我意识到C语言笔试拼的不是智商而是你平时积累的工程手感——谁能少出内存错误谁就能走到最后。