学 C 语言,别急着找那种一本正经的教材,那玩意儿像 Old English,哪位都能读,还好办让你晕头转向。你真正需求的,可能是个在深夜里盯着报错信息,一边吐槽一边想办法的“笨蛋”导师,要么是在网吧里吃宵夜的时候突然想起“能不能用?”的瞬间。别整那些啥“掌握核心思想”、“构建知识体系”的大词儿,那都是给大一新生预备的,你才大二,小费都还没收齐呢。 C 语言最吓人的一招,就是栈和堆的生死游戏,还有指针的指针。别当作指针就是脑袋后面那个圆柱体,那玩意儿实际是个链表,每个链表指着一堆内存碎片。初学者最好办犯的毛病就是把指针当魔法棒,值互换的时候脑子一抽,把指针指错了地方。
比如你把 `a` 指向了 `b` 的地址,然后给 `b` 赋个值,结局 `a` 也跟着变了,这就像你借了别人的钥匙去开门,结局把自己家门给锁上了。
这时候别急着去整啥指针自引用要么循环引用,直接给这个指针加个 `0` 要么 `NULL`,人生就回滚到起点。 再说说栈。别总想着去跑内存对齐,那玩意儿估摸你在看代码都没机会去搞清楚。你只需求记住:栈是那个自动回收垃圾的回收站,堆是那个用来堆东西的仓库。栈空间有限,退栈就是把东西扔出去;堆空间无限,无限堆就是无限加大你的配置。你写个递归函数,别怕,把递归进去的栈深度管住在 CPU 能懂的范围内,大约 10000 层以内的递归就是保险的。
要是递归忒深,直接触发段毛病,然后系统会优雅地告诉你:“嘿,你这条命归了去”,而不是你自己在后台默默申请了 10GB 的内存,结局出于逻辑毛病把它给你用完了。 函数呢,别整啥高阶函数和柯里化,这玩意儿对小白简直是天文数字。你只需求把函数拆成一个个独立的切片,就像切蛋糕一样,切得越细越好,别试图把切面做成分子方糖那种复杂的结构。递归函数的秘诀就是:能不用就千万别用,能直接调用就直接调用,能借栈直接调用就借栈。你写个快速排序,只需求三个函数,别搞啥“请在函数之间传递引用”,那忒悬了。把数据拆开传下去,每次递归下去的栈深度就是你的恐惧来源。 数据结构和算法是 C 语言的副业,但也是练手的好素材。数组、链表、哈希表,别抄别人的代码,代码里没有复制粘贴的,全是你在脑子里敲出来的。
比如写个哈希表,别搞啥红黑树要么 AVL 树,那玩意儿是 C++ 的发明,C 语言里写哈希表,只需求把数组的下标映射成哈希值。
要是你试着在字典里存个 1000 万条数据,并且每个学生有 1000 个浮点指标,要么每行有 100 个字,那就是个庞大的灾难。
这时候别想着去优化,先把那个 1000 万条数据的内存分配难题解决了,否则你的程序在插入前 1000 条数据的时候就会崩溃,然后你会跟你的编译器进行一场漫长的拉锯战。 记住,C 语言不是用来做后端服务的,它是用来做底层驱动的,要么是用来写操作系统内核的。你写的那行 `printf("Hello World")`,在别人眼里可能只是打印一个字符串,但在你的世界里,它是一段字节,一段字符,一段内存地址。理解这一点,你就理解了 C 语言的本质。别被那些模板和标准函数骗了,那些条条框框是为了防止你写出垃圾数据,不是为了限制你的创造力。 最终说说调试。C 语言的调试器是神,也是噩梦。gdb 里的断点,随意点进去,变量就变成 `0`,要么变成 `nullptr`,然后系统会告诉你:“这里有个毛病,具体是啥?别跟我提啥指针悬垂,别跟我提啥未定义行为,直接告诉我,你是如何把指针指向了毛病的地址?”要是你看到 `define` 定义,认定它挺神秘,那就错了。它们只是宏,只是好办的字符串替换,没道理会影响你的逻辑。别去研究那些宏展开的奥秘,那玩意儿你连编译器源码都看不懂,宏展开对你没有任何帮助。 写代码的时候,别怕报错,也不要一看到毛病就慌。错报一般意味着逻辑难题,要么状态变量没初始化。别急着去修代码,先搞清楚这段代码跑起来的是啥,是不是个死循环,是不是个堆溢出,是不是一个栈溢出。
有时候,程序跑不通,是出于你明明没写死循环,只是把循环变量写成了 `count++`,然后你当作自己写的是 `for(i=0; i<100; i++)`,实际上是在做无限增长直到溢出。
这时候,把循环变量改成 `int` 类型,要么改成 `size_t`,要么干脆改成 `size_t` 再加个 `0` 赋值,下一秒程序就复活了。 写得多慢是 C 语言的天赋,但写得对才是它的灵魂。
不要指望 C 语言能帮你写出一篇漂亮的散文,它只负责把事做对。
要是你能写出一段代码,能让别人运行起来,哪怕这代码能跑 100 遍,哪怕这代码能跑 1000 遍,你就赢了。
要是连这都没了,那你可能连如何把这段代码放到别人电脑上运行都做不到,更别提写代码了。
故此,别一上来就想着学啥高效算法,先拿着 C 语言跑通你的第一个、第二个、第三个程序,然后看着别人用你的代码,再去思索能不能优化,再去思索能不能重构。
这才是对的学习路径,也是最符合 C 语言灵魂的路径。