C 语言是所有高级语言的祖宗。Linux、macOS、Windows、MySQL、Redis、Python 解释器本体,全是 C 写的。它不藏着掖着,把内存、指针、编译过程全摊开给你看——学完 C,你才算真的"看得见计算机在干活"。本页以 C11 为基线,顺带讲 C23(2023 年最新标准)的新东西,编译器要求 GCC 14+ / Clang 18+。
第 1 节 · 为什么学 C,以及把环境搭起来
Why C · Setup · Hello World · Build Pipeline
第 2 节 · 基础语法:变量、运算符、流程控制
Types · Operators · Control Flow
第 3 节 · 数组与字符串:C 里没有 string 类型
Arrays · Strings (char[])
第 4 节 · 指针:C 的灵魂,也是新手的鬼门关
Pointers — The Soul of C
第 5 节 · 函数:把活儿打包,自己调自己也行
Functions · Recursion · Storage Classes
第 6 节 · 结构体、共用体、枚举、typedef
struct · union · enum · typedef
第 7 节 · 内存管理:C 程序员的成人礼
Memory Layout · malloc / free
第 8 节 · 文件 IO:让数据活过程序这次运行
File I/O with FILE*
第 9 节 · 预处理与宏:编译前的文字替换
Preprocessor · #define · #include
第 10 节 · 位运算:直接掰扯二进制
Bitwise Operations
第 11 节 · 数据结构实战:用 C 手撸一遍
Linked List · Stack · Queue · Tree
第 12 节 · 小项目:学生成绩管理系统
Mini Project — Grade Manager
第 13 节 · 工具链实战:Makefile、gdb、valgrind
Makefile · gdb · valgrind
第 14 节 · 常见坑与最佳实践
Pitfalls & Best Practices
第 15 节 · 构建系统:Make 与 CMake
Makefile · CMake · CMakeLists · targets & linking
第 16 节 · 未定义行为与 Sanitizers
Undefined Behavior · ASan · UBSan · TSan · Valgrind
小结与自测
这一页从 Hello World 讲到手撸链表,核心就一句话:C 把内存摊开给你看,你学会了自己管它。指针和内存管理是分水岭,过了这两关,C 就算入门了。下面 5 道自测题,点开 details 对答案,错了就回翻对应章节。
1.(指针题)下面代码运行后,x 的值是多少?
查看答案
答案:20。p 存的是 x 的地址,*p = 20 就是"按这个门牌号进去,把里面改成 20",改的就是 x 本身。解析:这正是指针能"改外面变量"的原理。
2.(内存题)为什么说 malloc 和 free 必须配对?只 malloc 不 free 会造成什么后果?
查看答案
答案:malloc 是向堆申请内存,free 是把内存还给系统。只申请不归还,就是内存泄漏——程序每跑一次就占着一块内存不撒手,跑久了可用内存越来越少,最终被系统杀掉。解析:C 没有垃圾回收,借了就得自己还。
3.(字符串题)char s[5] = "hello"; 这行为什么有问题?
查看答案
答案:"hello" 是 5 个可见字符,但 C 字符串末尾还要一个 '\0' 结束符,实际需要 6 个字节。数组只有 5 格,'\0' 被挤出去了。后果:printf/strlen 读到 s 后会继续往内存里乱读。正解:写成 char s[6] = "hello"; 或直接 char s[] = "hello";(编译器自动算 6)。
4.(编译题)编译一个 C 程序有哪四个阶段?报 undefined reference to 'xxx' 是在哪个阶段?
查看答案
答案:预处理 → 编译 → 汇编 → 链接。解析:undefined reference(未定义的引用)是链接阶段报的——你调用了某个函数,但找不到它的实现(库没链上、函数忘了写、拼写错)。它不是语法错,所以前面阶段都通过了,最后拼接时才发现"缺零件"。
5.(思维题)C 函数传参是"值传递",那为什么 swap 函数传 &a, &b 就能真正交换外面的变量?
查看答案
答案:传进去的虽然还是"副本",但这个副本装的是地址。swap 里通过 *a、*b 解引用,操作的是地址指向的那块真实内存,所以外面的 a、b 被改了。解析:值传递本身没变,变的是"传的是门牌号的副本"——拿着副本门牌号,照样能进那间房。
下一步往哪走
路学完 C 之后
① 想往系统/底层:接着学 C++(下一页)或直接读 Linux 源码、写个简单 shell。
② 想往应用开发:C 打底后转 Python/Go 会非常快——你会比别人多懂一层"为什么这样设计"。
③ C23 新东西:有空翻翻 nullptr、constexpr、#embed,但它们不是入门门槛,先用熟 C11 再说。