|
我第一份工作面试时,学c语面试官问我:“你用过指针吗?学c语”我说用过。他递过来一张纸:“写个字符串反转。学c语”我写了十行,学c语里面有三个野指针。学c语他没说话,学c语把纸推回来,学c语上面画了个叉。学c语那天我才明白,学c语C语言不是学c语“学过”就算会的。 很多人推荐Python入门,学c语理由是学c语语法简单、见效快。学c语这话没错。学c语但如果你想真正理解计算机在干什么,学c语绕开C语言基本等于自欺欺人。Python里一个a = [1,2,3],你不需要知道内存怎么分配、列表对象占多少字节、引用计数怎么增减。C语言不给你这层遮羞布。你声明一个int arr[3],它就是栈上12个字节,不多不少。越界写入?程序可能当场崩溃,也可能悄悄改掉隔壁变量的值,让你查三天三夜。 我见过太多人写Java写了好几年,遇到OutOfMemoryError就只会加-Xmx。他们不知道堆和栈的区别,不知道内存碎片怎么产生,不知道一个对象头占多少空间。这些知识在C语言里是必修课。你得手动malloc和free,得理解为什么free之后指针要置NULL,得体会内存泄漏是怎么一点点吃掉系统的。这种“痛感”是其他语言给不了的。 学C语言还有一个好处:你会开始敬畏硬件。写Python时你不太在意一个循环跑一百万次和跑一亿次的区别,反正底层有优化。C语言里,一个for循环里多一次strlen调用,性能就能差出几十倍。我做过一个文本处理的小工具,第一版用strlen判断字符串结尾,处理100MB文件花了8秒。后来改成用指针遍历,直接降到0.3秒。这种反馈是即时的、粗暴的,逼着你去想数据在内存里到底怎么摆。 当然,C语言不好学。它的语法坑多,标准库又小得可怜。你想做个网络请求?自己调socket API。想解析JSON?找个第三方库或者手写。指针和数组的暧昧关系能逼疯新手——arr和&arr类型不一样,但值一样;arr在表达式里会退化成指针,但sizeof又不会。这些规则没有为什么,就是语言设计的历史包袱。你得背,得踩坑,得在段错误里泡够了才能记住。 但恰恰是这些“不友好”,让你对计算机的理解从黑箱变成白箱。你知道函数调用时栈帧怎么压,知道结构体对齐会浪费多少字节,知道volatile什么时候必须加。这些知识不会过时。后来我转去写Go、写Rust,发现底层逻辑全通——goroutine的栈、Rust的所有权,本质上还是在跟内存打交道。C语言教你的不是语法,是计算机的物理直觉。 如果你只想快速做个网页、写个爬虫,那别学C。但如果你想弄明白程序到底怎么跑起来的,想有一天能读懂Linux内核源码,想写出真正高效、可控的代码,C语言是绕不过去的坎。它像一把没有护手的刀,容易割伤自己,但用熟了,你才知道什么叫“精确控制”。 我现在的建议很直接:花两周把《C程序设计语言》过一遍,然后找个开源项目读代码,比如redis的sds或者nginx的内存池。别停留在做课后习题。真正的C语言在那些地方活着——在指针的跳跃里,在内存布局的算计里,在每一行都可能是bug的紧张感里。 |