跳转到内容

进阶阶段 — Unit 2: C Essentials(数据结构与算法核心训练)

"Programs = Data Structures + Algorithms." — Niklaus Wirth(Pascal 之父,图灵奖得主)

课程总览

课号模块题目难度核心知识点
25字符串实现 my_strstr滑动窗口双重循环、i<=n-m 边界、O(n·m) 最坏退化、NUL 终止符、KMP 思想简介
26内存实现 my_memcpy易-中void*→char* 转换、逐字节拷贝、const 语义、size_t 类型、浅拷贝 vs 深拷贝
27内存实现 my_memmove三重叠情形、正向级联污染、反向拷贝证明、三分支方向判断、memcpy vs memmove
28回溯全排列问题回溯三步(swap→递归→swap back)、排列树 n! 叶、去重剪枝、O(n·n!) 下界
29回溯八皇后问题一维棋盘约简、对角线公式
30链表单链表插入易-中头插 O(1) 反序 vs 尾插 O(n) 保序、空表边界、C 值传递返回 head、哨兵节点
31链表单链表查找与删除prev 滞后一步、删除五情形(头/中/尾/独/未找到)、free 顺序、双向链表 O(1)
32链表链表反转与环检测中-难 【面试高频】三指针反转、Floyd 快慢指针、环入口定位证明、快慢针延伸(中点/倒数第 k/回文)
33链表循环链表与约瑟夫中-难自环最小合法态、do-while 遍历、数据结构选型对比、约瑟夫 O(N) 递推
34括号匹配易-中LIFO=最近配对、三种失败模式、数组栈 top=-1、HTML/XML 推广、O(n) 分析
35队列环形队列基础易-中FIFO 语义、假溢出→取模回绕、"先放后推"顺序、牺牲一槽区分空满、Linux kfifo
36二叉树 DFS 遍历易-中三种遍历仅 printf 位置不同、前+中唯一重构、非递归栈遍历、Morris O(1)、序列化
37二叉树层序 BFSBFS=队列 vs DFS=栈、队列泛化 int→node*、按层分组 rear-front、完全二叉树检测
38BST 增删查左≤根≤右、递归插入/搜索 O(h)、删除三情形、双子右子树最小值替换、退化→AVL
39堆与 Top-K完全二叉树↔数组映射、heapify 下滤、build_heap O(n) Σ 证明、小顶堆 Top-K 陷阱
40查找二分查找O(log n)每步减半、mid 防溢出(JDK-5045582)、lo<=hi 等号、lower_bound 变体
41排序快速排序中-难Lomuto 划分、pivot 落最终位、O(n²) 最坏→随机化修复、Lomuto vs Hoare、introsort
42标准库snprintf 安全易-中sprintf 溢出灾难谱系、ret=企图长度(核心考点)、ret>=size 截断判定、pre-sizing
43标准库strtok_r 切分易-中原地修改 \0 替换、delim 字符集、saveptr=线程安全、字面量段错误、CSV 局限
44标准库qsort 泛型排序void*+size+cmp=C 泛型、(const char**)a 两级解引用陷阱、指针级数表
45标准库realloc 扩容致命 arr=realloc(arr,size)、安全 tmp 模式、倍增摊还 O(1)、1.5× vs 2×
46标准库sscanf 解析易-中%[^X] 扫描集、返回值=金标准、%s vs %[^:] 差异、宽度限制防溢出、赋值抑制
47机制setjmp/longjmp返回两次机制、恢复 SP/PC 空投锚点、jmp_buf 必须 global、C++ try/catch 起源
48I/OI/O 缓冲性能syscall 量化(fgetc 20M vs fread 5K)、三种缓冲模式、setvbuf 黄金规则、fgetc int

24 道题 × 7 大模块,从零实现数据结构到重写 C 标准库。每题采用 stdout 评测模式,平均编写约 25 行 C 代码。

一、阶段定位与目标

本阶段是 C 语言训练营的第三站,承接 Unit 1(C Fundamentals)建立的 C 语言核心语法与状态机思维,正式进入数据结构与算法的系统学习。如果说 Unit 1 是"掌握 C 语言全貌",那么 Unit 2 就是"用 C 语言组织数据、驾驭算法"——从零实现工业级数据结构,亲手重写 C 标准库关键函数。

根据训练营总体规划,本阶段旨在解决"学员会写 C 代码但不懂数据组织与算法设计"这一核心问题。设计思路为:结构为纲,算法为目——每引入一个数据结构,立刻用经典算法将其激活。

主要目标

  1. 掌握经典数据结构的从零实现:单向链表、循环链表、栈、环形队列、二叉树、二叉搜索树(BST)、堆。不只是"会用",而是"会造"——每个结构都用纯 C 语言的 struct 与指针从零搭建,理解每一行代码背后的内存布局。
  2. 掌握经典算法的设计思想:回溯(全排列、八皇后)、分治(快速排序)、剪枝、二分查找、广度优先搜索(BFS 层序遍历)、深度优先搜索(DFS 递归遍历)、Top-K 堆筛选。理解"同一问题多种解法"的工程取舍。
  3. 深入 C 标准库的底层机制:从 memcpy / memmove 的内存重叠处理,到 snprintf 的截断检测、strtok_r 的线程安全、qsort 的泛型比较器、realloc 的安全扩容、sscanf 的高级格式、setjmp / longjmp 的非局部跳转、标准 I/O 缓冲性能——七个练习带你读懂 glibc 的实现哲学。
  4. 为后续阶段铺路:本阶段的 24 个 Lesson 覆盖了 Unit 3(CS 经典问题)所需的全部数据结构基础(堆、散列、树、图遍历),并为 Unit 4(编译器实现)中的 AST 树结构、符号表(散列表)、递归下降解析等核心技术打下根基。

授课形式

与 Unit 1(C Fundamentals,两节直播)类似,本阶段采用腾讯会议直播授课,共四节:

节次时间内容
第一节2026 年 07 月 03 日 20:00Lesson 25-30:字符串与内存操作、递归回溯、链表入门
第二节2026 年 07 月 06 日 20:00Lesson 31-36:链表进阶、栈与队列、二叉树遍历
第三节2026 年 07 月 08 日 20:00Lesson 37-42:树进阶与堆、查找与排序、标准库入门
第四节2026 年 07 月 10 日 20:00Lesson 43-48:标准库深入与工程实践

每节直播约 2 小时,包含数据结构图解、算法推导、代码实战、现场答疑。直播录像会回传至训练营知识库供回看。

学习依托

  • 训练营维护的 clings 练习仓库(24 个 Lesson,共 24 道题)
  • 每个 Lesson 配套的 README 讲义(含算法图解、内存布局分析、课堂讨论与课后练习)
  • CNB 云原生开发环境(一键开箱)或本地 GCC 环境

二、主要内容与学习路径

本阶段通过 24 个递进式 Lesson,覆盖以下知识模块:

字符串与内存操作(Lesson 25-27)

Lesson 25 — 实现 my_strstr(1 道题)

  • 实现暴力字符串匹配:双重循环滑动窗口。
  • 掌握外层循环终止条件 i <= n - m(等号不可丢)、内层逐字符比较。
  • 理解时间复杂度 (O(n \times m)) 与最坏情况("AAAA...A" 匹配 "AAB")。

Lesson 26 — 实现 my_memcpy(1 道题)

  • 实现 C 标准库 memcpyvoid* 转换为 char* 逐字节拷贝。
  • 理解 void* 不能做算术运算的原因、const 修饰符的语义、size_t 类型。
  • 返回 dest 而非临时指针,保持与标准库一致的接口契约。

Lesson 27 — 实现 my_memmove【重点】(1 道题)

  • 实现 C 标准库 memmove:处理源与目的内存区域重叠的情况。
  • 核心判断:dest < src 正向拷贝,dest > src 反向拷贝,避免覆盖未读数据。
  • 理解 memcpymemmove 的本质区别——这是面试高频考点。

递归与回溯(Lesson 28-29)

Lesson 28 — 全排列问题(1 道题)

  • 回溯算法入门:选择 → 递归 → 撤销(swap back 恢复现场)。
  • 理解"回溯三步曲"与暴力枚举的区别:回溯保证进入下一层和回到当前层时状态都正确。
  • 掌握排列树的递归结构,为 Lesson 29 八皇后打基础。

Lesson 29 — 八皇后问题【标杆题】(1 道题)

  • 回溯 + 剪枝的经典应用:逐行放置皇后,冲突检测提前剪枝。
  • 冲突检测:同列 col[i] == c,同对角线 |row - i| == |c - col[i]|
  • 理解剪枝的威力:暴力 (8^8 = 16{,}777{,}216) 种可能,回溯剪枝仅探索约 15,000 个节点,剪枝率 > 99.9%。

链表(Lesson 30-33)

Lesson 30 — 单链表插入(1 道题)

  • 头插法(O(1),结果逆序)与尾插法(O(n),结果顺序)的实现与对比。
  • 理解 malloc 动态分配节点、指针链接的内存操作。

Lesson 31 — 单链表查找与删除(1 道题)

  • 按值查找、按索引查找、节点删除(维护前驱指针)。
  • 掌握三种删除边界:删头节点(prev == NULL)、删尾节点(prev->next = NULL)、删唯一节点(head = NULL)。
  • 理解 free 与指针修改的顺序——先改指针再释放内存。

Lesson 32 — 单链表反转与环检测【高频题】(1 道题)

  • 三指针反转法:prev / curr / next 逐节点翻转指向。
  • 快慢指针(Floyd 龟兔赛跑)环检测:快指针走 2 步、慢指针走 1 步,有环必相遇。
  • 这是面试最高频的链表题之一。

Lesson 33 — 循环链表与约瑟夫环(1 道题)

  • 循环链表的插入(自环初始化)与删除(找前驱遍历)。
  • 约瑟夫环算法:每轮走 K-1 步到达被淘汰者,打印并删除,直到链表为空。
  • 理解循环结构"尾节点指向头"的特殊性。

栈与队列(Lesson 34-35)

Lesson 34 — 栈实现括号匹配(1 道题)

  • 栈的经典应用:左括号入栈,右括号弹栈匹配。
  • 掌握栈的基本操作(push / pop / is_empty)与三种匹配失败情况。
  • 理解"栈是 LIFO 后进先出"的本质——这是编译器括号检查、表达式求值的基础。

Lesson 35 — 环形队列基础(1 道题)

  • 数组实现的环形队列:front / rear 双指针 + 取模运算实现环绕。
  • 入队 rear = (rear + 1) % MAX,出队 front = (front + 1) % MAX,队空 front == rear
  • 理解取模的意义:循环复用数组空间,避免线性队列"假溢出"问题。

树与堆(Lesson 36-39)

Lesson 36 — 二叉树前中后序遍历(1 道题)

  • 递归实现三种 DFS 遍历:前序(根左右)、中序(左根右)、后序(左右根)。
  • 理解三种遍历只是"访问根节点"的时机不同——只差一行代码的顺序。
  • 这是理解递归与树结构的入门关。

Lesson 37 — 二叉树层序遍历(1 道题)

  • BFS 广度优先遍历:用队列辅助,逐层访问。
  • 队列存储 struct node*(指针),出队打印后左右孩子入队。
  • 对比 Lesson 36 的 DFS(递归/隐式栈)与 BFS(显式队列),理解两种搜索策略的本质差异。

Lesson 38 — 二叉搜索树操作(1 道题)

  • BST 的插入、查找、删除(难点)。
  • 删除三种情况:叶子节点直接删、单子树返回子树、双子树用右子树最小值替换。
  • 理解 BST 的有序性:中序遍历得到有序序列。

Lesson 39 — 堆与 Top-K 问题(1 道题)

  • 小顶堆的 heapify(向下调整)与 build_heap(自底向上建堆)。
  • Top-K 算法:用大小为 K 的小顶堆维护 K 个最大值,堆顶即门槛。
  • 理解"为什么用小顶堆而非大顶堆"——堆顶是 K 个中最小的,作为筛选门槛。

查找与排序(Lesson 40-41)

Lesson 40 — 二分查找(1 道题)

  • 迭代二分查找:每次将搜索范围缩小一半。
  • 三个关键陷阱:mid = lo + (hi - lo) / 2 防溢出、循环条件 lo <= hi 带等号、更新用 mid ± 1 防死循环。
  • 理解为什么大厂面试必考二分——边界条件是 Bug 重灾区。

Lesson 41 — 快速排序(1 道题)

  • Lomuto 分区方案 + 递归快排。
  • partition:选 arr[hi] 为 pivot,i 维护"小于等于区"右边界,扫描交换。
  • 时间复杂度:平均 (O(n \log n)),最坏 (O(n^2)),空间 (O(\log n)) 递归栈。

标准库深入(Lesson 42-48)

Lesson 42 — snprintf 格式化安全(1 道题)

  • snprintf 的安全用法与返回值语义:返回"企图写入的字符数"。
  • 通过 ret >= size 判断是否截断,理解为什么大厂严禁 sprintf
  • 缓冲区溢出是 C 语言最常见的安全漏洞——snprintf 是防御的第一道防线。

Lesson 43 — strtok_r 线程安全切分(1 道题)

  • strtok_r 的使用:saveptr 保存切分位置上下文,首次传字符串、后续传 NULL
  • 理解 strtok 为什么不是线程安全的(内部 static 变量),strtok_r 如何解决。
  • 掌握命令行解析的核心技术——为 shell 实现铺路。

Lesson 44 — qsort 泛型排序(1 道题)

  • qsort 的比较器函数(comparator):int 数组与 char* 字符串数组。
  • 重点理解 char* 数组排序时 *(const char **)a 的双重解引用——这是指针理解的试金石。
  • 常见错误:写成 (const char *)a 会拿到半个指针导致段错误。

Lesson 45 — realloc 动态扩容(1 道题)

  • realloc 的安全用法:用临时变量接收返回值,成功才赋值。
  • 致命错误 arr = realloc(arr, new_size):失败时返回 NULL 导致内存泄漏。
  • 理解原地扩容 [in-place] 与异地搬迁 [moved] 的区别,以及加倍扩容策略的均摊 (O(1))。

Lesson 46 — sscanf 高级解析(1 道题)

  • sscanf 的高级格式 %[^:]:匹配除冒号外的所有字符。
  • 一行解析 host:port,返回值代表成功匹配的字段数。
  • 理解为什么不用正则——sscanf 零依赖,简单场景完全够用。

Lesson 47 — setjmp/longjmp 非局部跳转(1 道题)

  • setjmp 设锚点(首次返回 0),longjmp 跨函数跳回(让 setjmp 返回指定值)。
  • 理解被跳过的栈帧不会执行,C++ 的 try/catch 底层就基于此机制。
  • 掌握异常处理的底层原理——这是从 C 走向 C++ 的桥梁。

Lesson 48 — 标准 I/O 缓冲性能(1 道题)

  • 对比逐字节拷贝(fgetc/fputc)与缓冲拷贝(fread/fwrite)的性能差异。
  • 10MB 文件:fgetc 约 1000 万次系统调用,fread(4KB) 约 2500 次——快 100-1000 倍。
  • 理解标准库三种缓冲模式(全缓冲、行缓冲、无缓冲)与系统调用的代价。

练习工具 — clings

  • 使用训练营基于 CNB 云原生开发环境的 clings 练习仓库进行交互式练习。
  • 通过 Rustlings 风格的"读报错、修代码、保存即验证"的方式逐题过关。
  • 训练营会自动统计您的完成情况并记入阶段成绩。

三、推荐学习资料

以下资料可作为本阶段的主要参考:

核心教材

  • 《数据结构与算法分析:C 语言描述》(Mark Allen Weiss):本阶段最契合的教材,用 C 语言从零实现链表、栈、队列、树、堆、散列表,覆盖排序与查找算法。强烈推荐边读边做练习。
  • 《算法》(Robert Sedgewick):普林斯顿大学经典教材,算法图解清晰,C 语言实现简洁。排序、查找、图算法章节尤其出色。
  • 《C 程序设计语言》(The C Programming Language, K&R):第 5-6 章深入讲解指针与结构体,第 7 章覆盖标准 I/O 与系统接口——是 Lesson 25-27、42-48 的最佳参考。

在线教程

参考资料(进阶)

开发环境搭建

  • 推荐使用 CNB 云原生开发环境(Fork 仓库后一键启动,无需本地配置)。
  • 本地开发推荐 Linux 环境(WSL2 + Ubuntu 或虚拟机),安装 GCC 和 Python 3.11+。
  • 安装 clings 练习工具:推荐使用 uvx clings@latest 命令(无需全局安装,隔离运行)。

四、学习方式与建议

  1. 先读讲义,再做练习:每个 Lesson 目录下的 README.md 包含算法推导、内存布局图解、状态转移分析和课堂讨论题。建议先通读讲义,理解数据结构的内存模型后再动手修改 .c 文件。

  2. 善用 clings 工具:进入 clings 的 watch 模式后,每次保存文件会自动编译和验证。遇到卡壳时按 h 查看提示,按 l 浏览题目列表,按 t 查看测试用例(TDD 开发)。

  3. 动手画内存图:本阶段是指针与内存的"进阶关"。链表的指针链接、树的孩子指针、堆的数组表示——每学一个结构,务必在纸上画出节点与箭头。Lesson 27(内存重叠)、Lesson 32(链表反转)、Lesson 38(BST 删除)尤其需要画图辅助理解。

  4. 理解递归思维:Lesson 28(全排列)、Lesson 29(八皇后)、Lesson 36(树遍历)、Lesson 38(BST 操作)、Lesson 41(快排)五个练习构成了"递归五连击"。学会用"基准条件 + 递归步骤"分解问题,是后续编译器递归下降解析的核心技能。

  5. 对照标准库源码:Lesson 25-27(字符串/内存)和 Lesson 42-48(标准库)共 10 个练习都是重写 C 标准库函数。完成后建议对照 glibc 或 musl 的真实实现,体会工业级代码的边界处理与性能优化。

  6. 按时参加直播:本阶段有四节腾讯会议直播课(07/03、07/06、07/08、07/10),建议按时参加以获得最佳学习效果。直播中会现场演示数据结构的构建过程和算法的逐步推导,并解答疑问。如无法参加,请务必在课后观看回放。

五、关于晋级与要求

晋级方式

  1. Fork 训练营的 Unit-2-C-Essentials 仓库,在云原生开发环境或本地环境中完成 24 道练习题。
  2. 提交代码到 main 分支并创建合并请求(PR),CI 系统会自动评分。
  3. 可多次提交,以最高分为准。通过后即可在 OpenCamp 晋级榜单上查看成绩。

评分标准

  • 共 24 个 Lesson、24 道题,每题通过 clings 自动评测。
  • 评测模式以标准输出比对(stdout)为主,部分题目检查返回值与编译验证。

重要提示

本阶段是 C 语言训练营的进阶关,题目从 19 行代码(Lesson 26 memcpy)到 118 行代码(Lesson 31 链表操作)逐步递进。24 道题覆盖了数据结构与算法的核心骨架——链表、栈、队列、树、堆、排序、查找,外加 7 个 C 标准库函数的从零实现。每题平均编写约 25 行 C 代码,关键不是代码量,而是理解每个数据结构的内存布局与每个算法的设计思想。认真完成本阶段后,您将具备独立设计和实现中等规模数据结构的能力,为 Unit 3(CS 经典问题)和 Unit 4(编译器实现)打下坚实的算法与工程基础。

六、训练营完整学习路线

本 C 语言训练营采用 "四阶段 + 双项目" 的成长路径,从零基础入门到亲手实现编译器与操作系统内核,共 6 个 Unit,共计 120 课。最终目标:学员同时具备用 C 语言实现编译器和从裸机搭建操作系统内核的系统级编程能力,形成"语言 → 算法 → 系统 → 编译器 → 内核"的完整知识闭环。

导学阶段

Unit名称课程数核心内容
Unit 0C Primer5 课 / 9 题最简程序、printf、循环、条件分支、累加求和

从"编辑 — 编译 — 运行"的全流程入手,通过 5 个最小可运行程序建立 C 语言的基本心智模型。使用 clings 工具交互式练习。

基础阶段

Unit名称课程数核心内容
Unit 1C Fundamentals19 课 / 40 题嵌套循环、函数、数组、指针、结构体、联合体、位运算、可变参数、预处理器、状态机

从九九乘法表到词法分析器,涵盖 C 语言核心语法特性。通过实现 printf、命令解释器、预处理器、词法分析器等项目,将语法知识转化为工程能力。两节腾讯会议直播授课(2026/06/29 和 2026/07/01)。

进阶阶段

Unit名称课程数核心内容
Unit 2C Essentials24 课 / 24 题链表、栈、队列、树、堆、排序、查找、回溯、C 标准库深入实现

系统学习经典数据结构与算法,从字符串内存操作(strstr/memcpy/memmove)到链表/栈/队列/树/堆的从零实现,再到快速排序、二分查找、Top-K 堆筛选,最终深入 snprintf/strtok_r/qsort/realloc/sscanf/setjmp/I/O 缓冲七个标准库函数的底层机制。四节腾讯会议直播授课(2026/07/03、07/06、07/08、07/10)。

专业阶段

Unit名称课程数核心内容
Unit 3C Classicals24 课哲学家就餐、停等协议、LL(1) 解析器、B+ 树、光线追踪、A*寻路、RSA、向量时钟、缓存模拟、Aho-Corasick、NFA→DFA、测试框架、缓冲区溢出、感知机、LU 分解、无锁环形缓冲、标记清除 GC、图灵机、FFT、Sobel 边缘检测、TF-IDF、量子比特、PoW 区块链、终端计算器

覆盖计算机科学 17 个子领域的经典问题,每题平均编写约 96 行 C 代码,为编译器项目建立广阔的 CS 视野。

项目阶段

完成前三个阶段后,进入双线并行的项目实践:

Unit名称课程数核心内容
Unit 4C Compiler24 课从零实现 C 编译器 nccl-cc:一棵 AST,四个后端,五个运行环境
Unit 5C Kernel24 课从零实现操作系统内核 Avatar OS:裸机引导到多核调度

Unit 4 — C Compiler 用约 4000 行 C 代码完整走通"预处理 → 词法 → 语法 → 类型标注 → 代码生成"全流程,支持 RISC-V / ARM / AArch64 / x86-64 四个后端和 Linux 用户态 + 裸机共五种运行环境。最终验证:用自己写的编译器编译约瑟夫环程序,在四个架构上得到相同结果。

Unit 5 — C Kernel 基于 Avatar OS 真实内核代码,分五个子阶段递进:裸机基础 → 内存与同步 → 中断与定时器 → 多任务 → 用户态与多核。代码取自 Avatar OS 仓库,支持 AArch64 / RISC-V 64 / x86_64 三架构在 QEMU 上验证。最终目标:一个能运行 busybox shell、在多核处理器上并行调度的完整操作系统。

Released under the MIT License.