
1. 期末复习C先搞懂这门课到底考什么每到期末周总能看到有人在群里问C怎么复习然后底下冒出各种答案刷题、背概念、看网课、抄代码。说实话这些方法我都试过有的有效有的纯粹是自我感动。C这门课跟高数不一样它既是语言课又是编程课考的不仅是记住了什么更是能不能写出来、能不能看懂别人的代码。先说个判断标准如果你的复习计划里只有看课本那大概率会翻车。C期末卷子一般由三块组成——概念选择题、程序阅读题、编程大题有些学校还会加改错题。概念题靠背确实能拿分但程序阅读和编程大题靠的是手感手感这种东西不亲手敲几十段代码是练不出来的。这篇文章写给谁给那些平时上课听了个大概、作业靠着抄或者辅助工具混过去、现在想临时抱佛脚的本科生也给那些学了一遍但感觉什么都没记住、想系统过一遍的读者。下面这套复习路线是我自己实践过、也帮好几个学弟学妹验证过的按这个节奏走两周时间足够把C从会写hello world拉到能在卷子上拿分的程度。2. 三阶段复习法从课本到考场的完整路线2.1 第一阶段知识框架搭建复习最忌讳的就是打开课本从第一章开始一个字一个字读。C教材前面几章讲的是基本语法跟C语言高度重合如果你之前学过C这部分可以快速跳过如果你直接学的C也要控制时间别在for循环、数组这些基础语法上磨太久。我建议先用半天时间把目录过一遍在纸上画出知识树。C期末考点大致分五个枝干基础语法数据类型、运算符、流程控制、函数重载、默认参数、内联、类与对象封装、构造析构、友元、运算符重载、继承与多态派生、虚函数、抽象类、模板与STL函数模板、类模板、容器、迭代器。把这五块列出来对照老师的课件标注哪些是重点哪些老师上课反复讲过哪些一带而过这就是你的复习地图。这里有个实用技巧找一份往年试卷或者课后习题集先别做题只看题目涉及的知识点回到知识树上做标记。你会发现考试的重心非常集中指针、类、虚函数这三块加起来能占50%以上的分值。剩下的时间重点砸在这三块上性价比最高。2.2 第二阶段代码实战训练框架搭好了接下来就是动手。这一阶段我用的方法是三遍代码法第一遍看。把课本上的例题、老师PPT里的代码、往年考过的程序题全部看一遍看懂每行代码在干什么这一步的目标是恢复读码能力。第二遍抄。合上书凭记忆把关键代码默写出来。注意不是复制粘贴是真正动手敲哪怕敲得慢、敲得错也要敲。敲完之后对照原文找出哪里记错了。第三遍改。把代码里的参数改一改、逻辑换一换比如把一个for循环改成while把一个数组改成vector看看会出现什么结果。很多同学觉得我看懂了就等于我会了这是最大的错觉。考试的时候程序阅读题是别人写好的代码让你分析编程题是给你需求让你凭空写代码这两件事考察的能力完全不同。第二阶段的核心目的就是把看懂转化为会写这个转化没有捷径只能靠量堆出来。2.3 第三阶段真题模拟与查漏补缺最后一周进入模拟阶段。找两到三份完整试卷严格按照考试时间来做中间不翻书、不查资料做完之后给自己打分。打分这件事很重要不是为了看分数高低而是为了定位问题。比如程序阅读题错得多说明你对语法细节的理解还有漏洞编程题写不出来说明训练量不够。针对暴露出来的问题回到第二阶段补练形成一个练习-检测-补漏的闭环。我见过很多人复习时只做选择题不做编程题理由是编程题太难了到时候靠蒙。这个思路非常危险。编程大题分值高、区分度大而且其实是最容易拿分的地方——因为C编程题的题型非常固定无非是字符串处理、数组操作、类的设计、继承多态的应用每一种都有固定的解题套路提前练过几道之后考场上遇到类似的题完全能套用。3. 核心考点逐个击破最容易丢分的几个地方3.1 指针、引用与内存管理指针是C复习里绕不过去的一座山也是期末失分的重灾区。很多教材在讲指针时都在强调指向这个概念但真正考试时考的是三件事指针与数组的关系、指针与函数参数的关系、动态内存分配与释放。指针与数组这块最经典的问题是数组名和指针到底有什么区别。答案是数组名在某些场景下会退化为指向首元素的指针但数组名本身是一个常量不能被重新赋值。比如int a[10]; int *p a;是合法的但a是非法的。这个细节在选择题里反复出现我每次复习都要提醒自己一遍。指针作为函数参数考察的是值传递和地址传递的区别。void swap(int a, int b)交换不了实参因为函数内部操作的是副本void swap(int *a, int *b)能交换因为操作的是实参地址指向的内存。这个例子几乎每年都考闭着眼都要能写出来。动态内存这块考的集中在new和delete的配套使用上。记住一个原则new出来的对象必须用delete释放new[]出来的数组必须用delete[]释放。两者混用属于未定义行为有时候编译能过但运行时会崩具体什么症状都不一定。写类的时候如果成员里有指针析构函数里必须释放内存这个后面讲拷贝控制时还会再遇到。3.2 类与对象构造、析构、拷贝控制类的设计是C期末的绝对核心选择题、阅读题、编程题都会涉及。复习这一块我建议抓住一条主线类生命周期的管理。一个对象的完整生命周期是申请内存、调用构造函数初始化、使用、调用析构函数清理、释放内存。构造函数有默认构造、有参构造、拷贝构造、移动构造有些学校不考移动析构函数只有一个。考试最爱考的是执行顺序——定义对象数组时每个元素依次调用构造函数作用域结束时析构函数按什么顺序调用全局对象和局部对象的构造析构先后关系这些都需要理清楚。拷贝构造函数是个重灾区。当函数按值传递对象、函数返回对象、用一个对象初始化另一个对象时都会调用拷贝构造函数。如果你没写编译器会生成一个默认的浅拷贝版本。对于只包含普通成员的类浅拷贝够用但一旦类里有指针成员浅拷贝就会导致两个对象的指针指向同一块内存析构时被释放两次直接double free崩溃。正确的做法是深拷贝在拷贝构造里重新申请一块内存把原对象指针指向的内容复制过来。这个知识点我建议一定要动手写一遍。class String { private: char *m_data; int m_size; public: String(const char *str) { m_size strlen(str); m_data new char[m_size 1]; strcpy(m_data, str); } // 深拷贝构造 String(const String other) { m_size other.m_size; m_data new char[m_size 1]; strcpy(m_data, other.m_data); } // 赋值运算符重载 String operator(const String other) { if (this ! other) { delete[] m_data; m_size other.m_size; m_data new char[m_size 1]; strcpy(m_data, other.m_data); } return *this; } ~String() { delete[] m_data; } };这段代码几乎就是编程大题的模板考运算符重载或者类的设计时直接套用。注意赋值运算符里那个if (this ! other)的判断这是防止自赋值的关键很多同学第一次写都会漏掉。3.3 继承与多态虚函数到底怎么考继承与多态这块概念题爱考封装、继承、多态的含义阅读题爱考派生类对象的构造析构顺序大题爱考虚函数的应用。构造析构顺序是必考的点创建派生类对象时先调用基类构造函数再调用派生类构造函数销毁时顺序相反先派生类析构再基类析构。这个顺序很多人会记反其实想一想就通了派生类是在基类基础上扩展的必须先打好底盘才能往上盖楼拆的时候必须先拆楼上的再拆地基不然楼会塌。虚函数考察的核心是动态绑定。当基类指针或引用指向派生类对象时调用虚函数会执行派生类的版本这就是多态。这里有个很隐蔽的考点构造函数里调用虚函数不会产生多态因为构造过程中对象的动态类型还是基类。这个知识点选择题里出现过不止一次遇到了别再踩坑。纯虚函数和抽象类的概念也经常考。含有纯虚函数的类是抽象类不能实例化只能作为基类派生类必须实现所有纯虚函数才能被实例化否则它也是抽象类。这个否则它也是抽象类的推论特别容易漏。class Shape { public: virtual double area() const 0; // 纯虚函数 virtual ~Shape() {} }; class Circle : public Shape { private: double r; public: Circle(double radius) : r(radius) {} double area() const override { return 3.14159 * r * r; } }; // 多态的典型用法 Shape *s new Circle(2.0); cout s-area() endl; // 调用Circle的area delete s;注意基类的析构函数要声明为虚函数这一步是为了保证delete基类指针时能正确调用派生类的析构函数。如果基类析构不是虚的delete s只会调用Shape::~Shape()Circle里如果申请了资源就会泄漏。这个细节在改错题里出现过注意一下。3.4 STL与泛型编程有些学校的C课程只讲到类就结束了STL放到下一学期但如果有STL的内容这其实是送分题。vector、string、map、set这几种容器的基本用法必须熟悉迭代器的遍历方式要会写。STL复习不需要多深会这几样就够应付容器怎么创建、怎么往里加元素、怎么用迭代器遍历、怎么访问元素。考试一般不考底层实现原理考的是能不能正确使用。唯一需要理解的概念是迭代器为什么不能用下标替代——有些容器比如list不支持随机访问只能用迭代器逐个移动这个在选择题里会以以下哪种说法正确的形式出现。泛型编程这里函数模板和类模板的语法要会套模板。基本格式是template typename T开头后面跟函数或类定义。有个容易记混的点模板的声明和定义最好放在同一个头文件里如果分开放在 .h 和 .cpp 里链接时会找不到定义。这个我在自己做小项目时踩过坑期末考试复习时特别留意了。template typename T T my_max(T a, T b) { return a b ? a : b; } // 调用时自动推导类型 cout my_max(3, 5) endl; // int版本 cout my_max(3.5, 2.1) endl; // double版本4. 实操训练手写代码的练习方法与复盘技巧4.1 从看得懂到写得出的转化我见过太多人复习时只看不写觉得自己都会了一上考场就抓瞎。编程是个手艺活跟游泳、骑车一样只有手上有感觉才算真会。所以我强烈建议复习期间每天至少手写两段完整的代码不是照着抄而是看完题目后在纸上写出来。期中的时候我帮一个学弟补习他最大的问题就是看得懂代码但写不出来。我让他做了一个练习每天用C实现一个小功能比如统计字符串里每个字符出现的次数、反转一个整数、判断一个数是不是回文数、实现一个简单的Student类并重载输入输出运算符。坚持了十天之后他的手感和逻辑思维明显好了很多。原因很简单看代码是被动接收信息写代码是主动组织信息后者对大脑的要求高得多。手写代码还有一个好处——能逼你关注语法细节。纸上没有IDE的自动补全和语法高亮写错了只能凭自己的知识发现。比如分号漏了吗、括号匹配了吗、作用域符写对了没有这些在IDE里轻轻松松就会自动补的东西纸上一写就知道自己有没有真正掌握。4.2 编译错误与运行错误的排查思路程序题做错了最常见的反应是代码贴上去编译一下看看报什么错但在期末卷子上没有编译器给你报错你得靠人眼模拟编译过程。这就需要在平时练习时有意识地训练人眼debug能力。拿到一段代码我习惯按这个顺序排查先看语法层有没有漏分号、括号不匹配、类型写错再看语义层变量有没有初始化、数组下标有没有越界、循环退出条件对不对最后看资源层new了有没有delete、文件打开后有没有关闭。这个顺序对应考试中的改错题。改错题一般藏着3到5个错误有的明显语法错误有的隐蔽逻辑错误。先抓语法错误因为这类错误一眼就能看出来能帮你建立信心再找逻辑错误比如循环里少了i、比较相等写了而不是、数组长度多写了1位。最容易忽略的是资源管理错误——函数中局部指针new了却没在函数结束前delete这类错误在改错题里出现频率很高。4.3 概念题与程序阅读题的正确刷法概念题看似简单但恰恰是最容易在不经意间丢分的。C的概念题有个特点选项之间的差别非常细微一个引用和指针的区别一个深浅拷贝的区别都是考察点。我的复习建议是把教材里所有定义性质的内容整理成一份速查表。比如什么是重载什么是覆盖什么是隐藏这三个概念特别容易混淆。重载是同一个作用域内函数名相同但参数列表不同覆盖是派生类中重新定义基类的虚函数隐藏是派生类中定义了一个与基类同名但不构成重载的函数此时基类的同名函数在派生类中会被隐藏。这三者的区别几乎每年概念题都会涉及整理成表格对照记忆效果最好。程序阅读题是C考试里分值最大的一部分也是最需要练的。这种题一般给一段代码让你写出输出结果或者解释程序功能。练这类题时我建议用变量追踪法拿一张草稿纸把程序里每个变量的变化过程一步步写下来模拟程序执行。不要只在脑子里想脑子会骗你纸上的记录不会。练多了之后你会发现程序阅读题的套路很固定要么考构造析构调用顺序要么考递归调用过程要么考指针修改值每种套路多练几道考试时就是纯粹的肌肉记忆。5. 常见问题与避坑实录5.1 指针相关的经典错误复习了这么多遍指针这一块有几个错误是我见过最多、也是最容易在考场上犯的第一个是空指针解引用。定义一个指针后没有初始化直接赋值或者访问指针可能是野指针指向随机的内存地址程序运行时会段错误崩溃。规范做法是定义时初始化为nullptr用之前检查是否为空。第二个是数组越界不报错就以为是正确的。C不像Java那样会主动检查数组下标越界你写a[10]访问第11个元素编译器可能什么提示都没有程序也能运行但那个位置的数据是不知道从哪里来的垃圾值。考试时如果结果不对先查数组下标的边界条件。第三个是delete之后继续使用指针。指针在delete之后成为悬垂指针它指向的内存已经被释放再用它访问数据是未定义行为。我见过一个很经典的考题程序先delete p然后又用*p 100赋值问你运行结果。答案是未定义可能正常也可能崩溃很多同学会直接说崩溃其实不对。复习时要注意这种未定义行为的表述它在选择题里是个高频选项。5.2 拷贝构造、深浅拷贝与临时对象深浅拷贝这个问题理论很好理解但一放到具体的题目里就容易出错。有一道经典判断题String b a;和String b(a);这两条语句是不是一样的答案是一样都会调用拷贝构造函数。而String b; b a;不一样第一句是默认构造第二句是赋值运算符调用。这里要特别强调赋值和初始化是两回事。变量声明时用是初始化调用拷贝构造声明之后再赋值才是调用赋值运算符。很多同学在这里栽跟头就是因为把两者混为一谈了。另外函数按值返回对象时会创建临时对象这个临时对象在C11之前会调用拷贝构造在C11之后会优先调用移动构造如果有的话。有些教材不讲移动语义但会在选择题里问临时对象相关的问题你至少要知道临时对象的存在以及生命周期——它会在当前全表达式结束时销毁。5.3 考试时间分配与答题顺序期末复习不只是复习知识还要模拟考场节奏。C试卷的题量一般比较大选择题20道、阅读题4到5道、编程题2到3道考试时间两个小时。按我的经验比较稳的分配方式是选择题40分钟、阅读题40分钟、编程题30分钟、检查10分钟。如果选择题卡住了先跳过别在一道题上耗太久。答题顺序上我的建议是先从阅读题开始做因为程序阅读题考察的是分析能力状态好的时候思路清晰能够快速拿分编程题放在最后因为编程需要思路完整如果先做编程题可能会因为过度紧张而卡壳。当然这个顺序看个人习惯关键是平时模拟考试时找到适合自己的节奏别到了考场才临时调整。6. 复习中的一点个人体会说了这么多方法和技巧最后想聊聊心态。C这门课的特点就是懂的人觉得很简单不懂的人觉得是天书。如果你现在觉得自己什么都不懂别慌这很正常。根据我帮过不少同学复习的经验哪怕平时一点都没学只要考前两周按搭框架-练代码-做模拟这个节奏走及格是大概率事件冲良好也完全有可能。但别想着走捷径。抄代码进考场是不可能的靠背答案应付编程题也是不现实的。唯一可靠的方法是脚踏实地地把每段代码亲手敲一遍把每个概念用自己的话解释一遍。当你能够不看课本写出一个完整的类、能够给别人讲清楚虚函数的工作原理时这门课你就算真正学进去了。最后分享一个小技巧复习时可以把C的关键语法和常见错误整理成一张A4纸的速查表放在床头或者手机里考前最后一天就看这张纸。它帮你把知识框架压缩成考前能快速过一遍的形式比抱着厚课本乱翻效率高得多。祝各位期末顺利。