尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C++入门精讲:从内存、指针到现代工程实践

C++入门精讲:从内存、指针到现代工程实践 1. C到底是什么为什么值得你花时间认识它1.1 一句话说清楚C是什么C是一门静态类型、编译型、支持多范式编程的语言。说得直白一点它是一门既保留了C语言底层控制能力又加入了面向对象、泛型编程、函数式编程等高级抽象能力的语言。你在网上搜“C”会看到大量“C你懂了吗”“C从入门到放弃”的帖子但真正把它用明白的人基本都是靠长期写工程代码喂出来的。我第一次接触C是在大学的数据结构课上。当时以为它只是“C语言加了个class”后来被多继承、模板、虚函数、迭代器一个个按在地上摩擦才慢慢意识到C的核心价值不是某一个语法特性而是它在“性能”与“抽象”之间提供了一条极其陡峭又极其诱人的平衡路径。你可以像写汇编一样控制内存布局也可以像写脚本一样用STL容器快速组织数据。这两种能力叠加在一起才是C至今仍在系统软件、游戏引擎、金融交易、嵌入式开发等领域不可替代的根本原因。这篇内容不用当成教材来读我按自己这些年踩坑和复盘的经验把C最关键的几个认知模块拆开讲清楚。适合想入门C的在校生、准备秋招看C岗的求职者以及从其他语言转过来的开发者。看完之后你对“C是什么、怎么学、去哪里用”会有一个比大多数人清晰得多的框架。1.2 C能做什么为什么到现在还是这么火C的应用领域比你想象中广得多。操作系统和底层组件Windows、Linux的内核以及大量基础设施虽然以C为主但很多系统级工具、文件系统、驱动模块都用了C。知名的MySQL、LevelDB、RocksDB等存储引擎底层核心代码都是C。游戏行业Unreal Engine、Unity的底层、自研引擎几乎都是C的天下。无论你玩《原神》还是《绝地求生》游戏客户端里热血沸腾的战斗逻辑、物理模拟、渲染管线跟C都有千丝万缕的关系。高频交易与量化系统一条交易指令从产生到发出延迟要控制在微秒级。Java和Python在这个量级的延迟控制上很难做到C是极少数的选择之一。浏览器与基础软件Chrome的渲染引擎Blink、JavaScript引擎V8都是用C写的。人工智能底层的算子库和推理引擎比如PyTorch的底层、TensorFlow的底层还有各类推理引擎都用C实现核心计算。Python只是外壳真正决定算得快不快的是底层C代码。传统工业与IoT汽车电子、医疗设备、机器人控制、各类嵌入式中间件C都是主力语言。你可能会想C这么难凭什么还有这么多人用答案很简单它能在代码抽象和硬件性能之间做最细腻的权衡。很多场景里你既想要高级语言的生产效率又想要接近底层的运行性能C就是目前综合成本最低的那条路。别提RustRust确实很优秀但要接到庞大的存量C代码生态里去还需要时间。C的学习曲线确实很陡但地基一旦建好能通的地方特别多这也是我建议新人不要完全绕开它的原因。1.3 不同基础的人应该怎么认识C如果你是纯新手完全没写过代码C不太适合作为第一门语言。我悟过的坑就是一开始直接啃《C Primer》看得头昏眼花指针那章反反复复翻了不下五遍还是懵。先学Python或者JavaScript建立基本的编程感觉再回来学C会顺畅很多。如果你是学过Java、Go、Python的开发者想补C能力那你的重点应该放在理解内存模型、指针/引用、RAII和模板这些Java/Go里没有或不强调的机制上。别再把精力浪费在for循环怎么写这种知识点上直接跳进核心机制。“认识C”这件事不要只理解为“学会语法”。语法只是门槛门槛后面还有编译原理的基础、操作系统的内存和进程知识、架构设计的取舍。C的美感恰恰在于它逼着你在写每一行代码的时候对数据流和生命周期有清晰的意识。带着这个心态往下看你会更容易理解后面的所有内容。2. 从历史到设计哲学三个视角看清C底层逻辑2.1 从“C with Classes”到C20一门语言如何演化至今C诞生于1979年。当时Bjarne Stroustrup在贝尔实验室工作觉得C语言写大型系统太啰嗦想给它加上类、继承之类的高级抽象取名“C with Classes”。1983年才正式改名为C名字里有“”也是个小幽默表示C语言的“自增”。这个出身决定了C基因里的两个方向一是完全兼容C二是提供面向对象的抽象能力。C在1998年才发布第一个正式国际标准ISO C98之后经历了2003年的小幅修订然后沉寂了很长时间。直到2011年的C11这门语言迎来真正里程碑式的大版本。自动类型推导、智能指针、移动语义、lambda表达式、线程库全都在C11里补齐了。业内常说“没有C11的C和C11以后完全是两门语言”不是没有道理。从那以后C14、C17、C20基本每三年出一版模块、概念、协程、范围等新特性陆续落地。了解这些历史的意义不在于记年份而是帮助你理解网上大量学习资料的“新旧之分”。如果你在网上看到讲“学习C必须先学指针再学引用”“不要用autovar会让人看不清类型”“new出来的对象必须delete”这类言论首先要判断它写于什么年代。C11之后的设计哲学已经强烈倾向于让程序员用更安全、更简洁的方式表达逻辑手动管理裸指针和new/delete被降到只在极底层场景才需要的程度。2.2 面向对象、泛型编程与资源管理C的三大支柱C最常被提起的三个设计支柱你会在任何教材里反复见到面向对象、泛型编程、资源管理。把这三根柱子理解透了C的学习地图就清晰了一大半。面向对象上C支持类、封装、继承、多态。多态的核心是虚函数和虚函数表。当你用基类指针调用虚函数时程序在运行时通过对象的虚函数表指针找到真正的函数入口实现“一身两用”的效果。这个机制让代码具备很强的扩展性比如你不用修改原有处理流程只需要新增一个派生类就能让系统支持新类型。Java、Go里的接口某种程度上就是在做类似的事只是C让你能看见背后的实现。泛型编程用模板实现。模板允许你在写代码时不指定具体类型而在编译时由编译器根据传入的类型自动生成对应代码。STL标准模板库就是泛型编程的集大成者。我们日常用的vector、map、string、sort都是模板。这带来极大的灵活性也会带来编译时间变长、报错信息极其恶心的问题。模板的复杂度是从入门到进阶、再到精通之间最大的一道门槛。资源管理方面核心思路是RAII资源获取即初始化。简单说在对象的构造函数里拿到资源内存、文件句柄、锁在对象生命周期结束时自动通过析构函数释放。C没有Java那种垃圾回收机制但这套由编译器保证的确定性析构机制在设计得当时比GC更容易预测资源的释放时机在高性能场景格外重要。C11之后进一步丰富了这套机制用智能指针把动态内存的资源管理也纳入进来。这三大支柱共同构成了一门语言在不同场景都能稳定输出的能力底座。2.3 性能与表达力的权衡理解C的设计哲学C的设计哲学可以用一句话概括不要为你不使用的东西付出代价。想手动管理内存没问题你拥有全部控制权。想用自动内存管理那用智能指针。想面向数据设计高效缓存友好型程序C给你操作内存布局的自由。想做高层抽象模板和继承体系也能支撑。这种哲学的结果是C不像很多语言那样强制你用一种风格写代码。一个C项目里可能同时存在C风格的流程代码、面向对象的架构代码、泛型算法代码和函数式风格的链式调用。这个特点既是优点也是灾难。优点在于灵活缺点在于团队协作时代码风格容易五花八门。所以真正规范的现代C项目通常都会有一套严格的代码规范比如Google C Style Guide约束“哪些特性可以用、哪些尽量别用”。理解了“不为不使用的东西付出代价”这条哲学你再看很多C做法就不会觉得混乱。为什么C不提供统一的垃圾回收因为垃圾回收需要运行时开销而很多场景压根就不需要GC。为什么C可以有那么多“未定义行为”因为你一旦要求编译器做足够多的安全检查那些极致性能的优化就做不了了。这是一场崇高的交易C选择把选择和风险都交给程序员。3. 认知升级C的关键概念与核心难点拆解3.1 内存与指针不懂内存就不算认识C如果只让我讲一个C最重要的基础概念我会选指针和内存。很多初学者问“指针到底有什么用”到了写底层代码阶段就会秒懂。CPU访问内存靠地址变量在内存里占一块空间这块空间的起始地址就由指针来保存。指针变量保存的是地址而不是值本身。这个模型用代码展示很直观#include iostream int main() { int value 42; int* ptr value; // 取地址ptr 保存 value 的地址 std::cout ptr std::endl; // 输出地址 std::cout *ptr std::endl; // * 解引用输出 42 *ptr 100; std::cout value std::endl; // 100 return 0; }指针难懂是因为它是对现实世界的间接抽象脑子里必须建立一层映射变量名哪里只是一个名字真实存在的是一个内存地址。为了安全C还提供了引用它类似于一个自动解引用的别名但底层本质上仍是指针只不过编译器帮你处理了解引用的细节。区别在于引用一旦绑定对象不能改绑指针可以重新指向别处。很多工程规范会建议能用引用就不指针必须用指针时也要尽量用智能指针替代裸指针。栈和堆的分工也必须在学C早期建立正确认知。局部变量默认在栈上分配函数返回就自动释放速度快但空间有上限用new或malloc创建的对象在堆上需要程序员决定何时释放空间更大但慢了。在C中如果使用RAII封装堆资源通常不需要手动释放对象生命周期结束时会自动清理。这套逻辑就是智能指针的工作原理。可以把内存想象成储物柜。栈上的变量像临时存包处你不用了自然有人收走堆上的东西像是自己租的仓库你不主动退租就会一直占着地方直到程序结束才被系统回收造成内存泄漏。3.2 类、继承与多态面向对象到底在解决什么问题面向对象编程本质上解决的是“数据与行为的组织问题”。用C语言写大型程序数据和行为往往是分离的你定义完结构体再写一堆函数去操作它。这种模式在规模小的时候没问题规模一大就很容易失控函数和数据的对应关系全靠命名约束出了问题很难查。面向对象把这两个东西封装在一起对象既是数据仓库又是行为接口。类的三个核心特性中封装对应权限控制用private/protected/public控制外界访问继承对应代码复用和层次抽象多态对应运行时行为的动态选择。这三个词不能只会背定义要能说出实际解决的问题。我见过很多面试者在简历里写“熟悉面向对象”但问“面向对象相比面向过程最大的优势是什么”只能回答“更安全、更符合人的思维”这种答案很难让人满意。更实际的答案是在大规模协作中封装把变化限制在局部继承和接口约定把替换的成本降到最低。多态的实现有一个关键点要想让多态生效基类的析构函数必须是虚的。否则删除一个基类指针指向的派生类对象时只会调用基类析构函数派生类申请的资源就不会被释放。这个看似细节的知识点是很多线上内存泄漏问题的起点。多态背后是动态绑定机制编译器为每个含有虚函数的类生成一张虚函数表对象的首地址区域里藏着一个指向该表的指针。理解了这一点你会发现网上那些“虚函数调用慢多少”的面试题背后考的就是这个模型。3.3 模板与STL泛型编程的强大与禁忌模板是C“把类型也作为参数”的实现方式。它的核心场景是写一份逻辑让它适配多种类型。比如写一个冒泡排序如果逻辑相同不要为int版写一份、为double版再写一份用模板一份就够了。这种做法在C语言里难以优雅实现在Java里要靠泛型擦除C则直接对类型像对值一样做编译期展开。STL是模板应用最杰出的成果。vector、list、map、unordered_map、deque、set这些容器几乎覆盖了所有常用数据结构的需求。还有算法库里的sort、find、transform等操作配合迭代器构成了从“数据”到“算法”的一套统一抽象。迭代器可以理解成容器的“游标”它把“怎么遍历容器”这件事封装成统一接口让算法能够不关心具体容器类型。你写sort(vector.begin(), vector.end())vector换成deque、list这段代码不用改顺序细节。使用STL也要遵守几个常识性禁忌。第一不要在遍历容器时修改容器的大小尤其是对vector、deque这些连续存储的容器进行push_back或erase很容易导致迭代器失效。第二不要把迭代器长期保存除非你清楚了解它的失效时机。第三vector的频繁扩容有性能开销如果提前能知道数据规模可以用reserve预留空间。我在实际工程里见过很多崩溃或数据错乱追查到最后都是迭代器失效问题。C给了你最锋利的工具也把一个屠龙刀那样危险的刃口交给了你使用前必须学会敬畏。3.4 现代C的必修课移动语义、lambda与并发C11引入的移动语义是一个改变命运的概念。移动语义背后的场景是很多时候我们并不想复制一个对象只是想把资源的所有权从一个对象“交接”给另一个对象比如把函数里的临时string作为返回值返回给外部变量。在没有移动语义的年代这个过程会触发一次深拷贝先复制到临时再复制到目标有了移动语义编译器可以直接把临时对象内部持有的堆内存指针“搬”到目标对象里成本从O(n)降到O(1)。移动语义配合右值引用和std::move是现代C高性能编程的核心。你需要理解的是std::move不是真的把对象移动到别处它只是告诉编译器“这个对象我们不再需要它的旧值你可以放心把它内部资源拿走”。真正执行移动的是类的移动构造函数或移动赋值运算符。如果你自己定义了一个管理资源的类不写移动构造函数就会退回到拷贝行为性能又回到从前。lambda表达式就是匿名的函数对象用来解决“在代码附近定义一小段逻辑”的需求。比如std::sort里传一个比较函数用lambda写比定义全局函数干净太多#include algorithm #include vector int main() { std::vectorint v {4, 1, 3, 5, 2}; std::sort(v.begin(), v.end(), [](int a, int b) { return a b; // 降序 }); return 0; }并发是C11才正式进入标准库的。std::thread可以创建线程std::mutex负责互斥std::async可以异步执行任务。并发编程最容易踩的坑就是数据竞争和死锁。多线程访问共享数据必须加锁加锁的顺序如果不一致就会死锁。C的并发模型还比较底层没有Java那种丰富的并发工具包这也意味着你必须有更扎实的OS功底。用一个频繁出现的面试题来说同一个变量多个线程分别一万次结果可能不是一万。原因就在于不是原子操作读、加、写三步可能被其他线程穿插。解决方法是加锁或用std::atomic原子类型但真正的底层原理还得回到CPU缓存一致性和内存序概念上去理解。4. 隐藏细节编译、链接与工程化认知4.1 源码到程序预处理、编译、汇编、链接四步走新手写C最容易忽略的就是“编译”这件事本身。很多人在IDE里一点运行按钮看到结果就以为自己懂编译了。真实情况是C从源代码变成可执行文件中间经历了预处理、编译、汇编、链接四个阶段。C没有Java那样的虚拟机解释字节码也没有Python那样运行时逐行解释它是一步一步把源代码翻译成本机器能直接执行的机器码的。预处理阶段处理的是以#开头的指令比如#include把头文件内容粘贴进来#define做文本替换。编译阶段把预处理后的源码翻译成汇编代码这个阶段也是各种语法和类型检查的主阵地。汇编阶段再把汇编代码转成机器码生成目标文件Windows下是.objLinux下是.o。链接阶段把多个目标文件和静态库合并到一起解析符号地址生成可执行文件。如果只写了一个.cpp文件链接问题可能不明显但当你拆分成多个模块、引入第三方库时链接错误就会频繁出现。理解链接阶段对排查“undefined reference to xxx”这类错误特别有帮助。这个错误通常意味着编译器看到了函数的声明但在链接时找不到函数的定义。常见原因有对应的函数没实现、忘了把实现文件加入编译、链接时没指定对应的库。很多人不懂为什么需要头文件与源文件的分离。头文件放声明源文件放定义这样每个源文件独立编译时只需要知道函数长什么样不需要知道函数体内的细节多个源文件可以并行编译也能隐藏实现细节。看C代码时先分清什么是声明什么是定义是阅读源码的重要前提。4.2 编译工具链和构建方式别只在IDE里点按钮C的编译离不开编译器和构建工具的配合。常用的编译器主要有这么几类GCC和GLinux生态的标配。GCC支持C语言G支持C语言底层共享同一个后端。Clang/LLVMmacOS和不少跨平台项目的主力编译工具。Clang的报错信息比GCC更友好深受很多开发者喜欢。新版Xcode默认使用的就是Clang。MSVCWindows上Visual Studio自带的编译器。MinGW-w64Windows上把GCC移植过来的一套工具链很多轻量级开发环境会使用它比如VS Code里最常见的编译器选择。构建方式上小项目直接在命令行用g main.cpp -o main编译即可项目文件一多就必须上构建工具了。CMake是当前跨平台C项目最主流的管理工具。它允许你通过CMakeLists.txt描述“项目有哪些源文件、依赖哪些库、编译选项是什么”然后自动生成对应平台的原生构建文件。相比手动写MakefileCMake的跨平台能力和声明式语法更友好。我第一次用CMake时觉得它麻烦配置一个Hello World折腾了半天。后来项目里要集成OpenCV、要跨Windows和Linux编译才发现CMake帮你挡掉的那些平台差异才是真正要命的复杂度。一个基础CMakeLists.txt长这样cmake_minimum_required(VERSION 3.16) project(MyProject) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(main main.cpp)用VS Code开发C时常用扩展是C/C由微软提供、CMake和CMake Tools。配置的思路是C/C扩展负责代码的智能提示、跳转和调试CMake Tools负责生成构建文件和编译任务。在Windows上安装好MinGW-w64后在CMake Tools里指定生成器为MinGW Makefiles基本就能顺畅跑起来。这一套配置好之后你不仅能编译单个文件还能应付多文件工程的复杂度这是从“写练习代码”迈向“写真实项目”的重要一步。4.3 调试与原理解析程序崩溃时怎么办写C永远不会调试就等于还没入门。最常用的调试手段是GDB命令行或IDE里的图形化调试。断点是最基本的工具在代码行设置断点程序执行到那一行就会暂停然后你可以查看变量的值、调用栈、内存内容。排除段错误之类的崩溃时查看调用栈能准确告诉你“是从哪个函数进入的、最终在哪一行炸的”比打log猜效率高太多。还要学会利用编译器和运行时给我们提供的安全检查机制。Debug模式下编译器默认做低级优化方便你打断点逐行调试。Release模式下编译器会开启O2/O3优化程序运行更快但调试信息会少很多。地址清理器AddressSanitizer是个神级工具编译时加上-fsanitizeaddress运行时能帮你看是否存在内存越界、释放后使用、内存泄漏等情况。我曾经在排查一个看似随机的崩溃时开了ASan之后立刻定位到“对一个已经释放的vector内部指针做了访问”这种事光靠肉眼读代码可能要读很久。学会阅读编译错误信息也很重要。C模板报错经常特别长一出错就是几百行。新手看到这些巨长的错误会慌正确做法是从第一个error开始看不要往下拉到最后一块看。模板报错通常会指向明显的类型不匹配位置找到第一个根源错误往往就能解决一片后续错误。说句大实话C调试能力是写出来的不是看出来的。如果你自己动手写代码的时间达不到几百小时看多少调试教程都会在实战里露馅。5. C能去哪里学了能做什么5.1 明确应用场景游戏、图形、基建、嵌入式C一个比较大的特点是它往往藏在幕后。普通用户输入的是界面上漂亮的按钮看到的是绚丽的渲染效果但这些背后的架构和接口很大概率是C支撑的。游戏行业里从渲染引擎、物理引擎到客户端逻辑层C无处不在。引擎框架里你会大量用到继承、虚函数、组件式设计物理模拟里你会和矩阵、向量、内存池打交道。能看懂这些代码基本就具备了游戏研发里较硬核的能力。图形图像领域也非常依赖C。OpenCV的核心接口是C做相机标定、图像处理写C代码和写Python的体验完全不同。Python调OpenCV更多是调用接口C写OpenCV则能让你触及像素操作、Mat数据结构和底层内存遍历的细节。很多人做视觉算法先用Python验证算法再由C工程化落地就是看重C的高性能和低延迟。嵌入式领域同样充满C。汽车电子、路由器、智能家电、无人机的控制程序大量使用C开发。C可以用来运行裸机程序也可以跑在Linux之上。这个领域更看重代码对资源的精准控制RAII和对象生命周期管理在嵌入式软件里格外受重视。5.2 后端、中间件与性能敏感系统互联网公司的存储系统、搜索引擎、推荐系统里的高并发链路底层都有C团队的身影。这类系统的核心诉求是单机性能要顶到极致Java和Go的GC暂停在某些超低延迟场景里是有压力的C没有GC配合对象池、无锁队列、零拷贝等技术可以获得很可观的性能表现。中间件开发也是一个重要方向。消息队列、缓存组件、RPC框架不少实现都倾向于使用C。Kafka的生态中用Java但RocketMQ的底层存储也有C实现的版本缓存组件Redis的代码是C但很多Redis模块、高性能代理组件则是C写的。如果你擅长数据结构和系统调优这类工作会很过瘾。量化交易系统的核心引擎几乎是非C不可。不管是盘口切片处理、策略信号计算还是订单路由延迟多一两毫秒可能就完全无法成交。量化团队里TopCoder和ACM银牌选手转行淬炼出的代码大概率在夜深人静的机房用C运行着。这个领域对C功底和数学功底的要求都很高但对初学者来说能确定“C可以通往这些高价值领域”本身就是一个很好的学习动力。5.3 学习路线与资源推荐如果你决定找一条务实的路线来学C我建议按下面这个节奏走第一步学基础语法包括变量、类型、运算符、流程控制、函数和数组。周期1到2个月写大量小练习。第二步攻克核心难点指针、引用、堆和栈、类和对象、继承、多态、运算符重载。周期2到3个月。第三步进入STL和泛型编程系统学习vector、list、map、string、算法、迭代器。周期1到2个月。第四步学现代C特性smart pointer、移动语义、lambda、线程、文件系统。周期1个月。第五步综合运用去GitHub读一些中小型开源项目的源码或找一些实际业务场景做小工具。能写一个基于Qt的桌面应用或者用OpenCV做一个图像处理工具对巩固工程能力会有非常大的帮助。书籍上新手可以考虑《C Primer》的前半部分这是一本大部头不必追求读完前12章能啃透就已经很强了。进阶可以看《Effective Modern C》和《Effective C》前者讲现代C的最佳实践后者是经典的经验集合。英文好的可以看The Cherno的C系列视频讲得比较清晰。不要盲目信网上的“21天精通C”C没有捷径多写才是唯一的捷径。6. 常见问题与避坑实录6.1 初学者最常见的几个问题学习C的过程中几乎每个人都会遇到下面这些问题指针到底有没有指向有效的内存 这是初学者最容易出问题的地方。起步阶段最常见的崩溃原因就是通过野指针或悬空指针访问内存。解决方案是指针定义时尽量初始化要么指向有效对象要么置为nullptr释放堆内存后要把指针置空防止后续误用。string和vector为什么要传引用 如果不传引用C默认会发生拷贝一次调用就是一次完整复制。对于大型对象这是性能和内存的双重损耗。函数参数按值传、按引用传、按const引用传一定要分清楚场景。为什么我的程序“偶尔”崩溃重新编译一下又好了 这大概率是未定义行为。C标准规定了很多“不要做”的事比如数组越界、有符号整数溢出、解引用空指针、已释放内存再次访问。未定义行为的表现可以是正常的也可以是崩溃的甚至可以是看似随机的错误结果。遇到这种问题时打开编译器的警告选项开启ASan逐项排查。为什么include头文件写了但还是提示找不到函数 可能是头文件只有声明没有实现也可能忘记链接对应的库。比如用OpenCV光把opencv2/opencv.hpp加进来还不够CMake里要链接opencv_world.lib才行。6.2 面试高频知识的自查清单C面试是八股文的重灾区但背后考察的内容确实和工程能力直接挂钩。我自己面过不少人也在面试中被问过相同问题整理了一份能自测的基础清单指针和引用的区别。堆和栈的差异及实际影响。虚函数多态的实现原理。静态成员和实例成员的本质区别。const在不同位置修饰的含义。析构函数为什么要用virtual。深拷贝和浅拷贝的区别以及何时必须提供拷贝构造函数。vector中push_back和emplace_back的区别。什么是移动语义std::move到底做了什么。智能指针的底层实现逻辑使用时机unique_ptr能否拷贝为什么。共享_ptr的引用计数如何保证线程安全。死锁的产生条件与规避方法。什么是迭代器失效在vector中插入元素会怎样。如何实现一个线程安全的单例。模板函数和模板类的常见用法。这些内容单看概念都不难难在问到深处。比如问到“虚函数表存在哪个区”“内存泄漏怎么排查”“用static变量实现单例时析构顺序如何保证”。这些问题就是看你有没有真正亲手写过错综复杂的代码。我的建议是每学一个新的C机制都要手写一个10到20行的小例子用调试器实际观察它的行为不要只背概念。6.3 学习过程中的心态建议C给你的挫败感在主流语言里算数一数二的。但换个角度想它给你的能力增量也是数一数二的。学C最大的误区是贪多嚼不烂今天看到模板牛就猛啃模板明天看到设计模式好用又开始磨设计模式后天看到新版本又出新特性又想去追。知识之间是有顺序的内存模型不稳学多线程会碰到天花板类与对象不稳学设计模式容易飘在空中。建议一次只攻一个专题写代码验证然后进入下一个。现在从最基础的“Hello World”开始一步步把这些知识点在代码里跑出来。遇到看不懂的报错是常态一次查不出来就拆小验证再查再验证。只要你肯花时间C一定不会让你失望。
返回列表