简介:这份资源是华南理工大学《C++程序设计基础》A卷期末试卷的PDF电子版,面向正在学习C++语法、准备课程考试或需要刷题巩固基础的高校学生。试卷为闭卷形式,共四大题、满分100分、考试时间120分钟,内容覆盖常量与变量、逻辑运算符、自增自减、条件运算符、for与while循环、switch语句、函数原型与重载、const关键字、数组与指针、字符串处理及结构体等核心考点,并附有逐题解析,帮助读者理解易错点与命题思路。资源包内共1个PDF文件,大小约288KB,轻量便携,适合打印或电子设备随时查阅。目前已有116人学习浏览,可作为期末复习、知识点自测与查漏补缺的参考材料,尤其适合需要对照真题梳理C++基础语法体系的学习者使用。
1. 一份 C++ 期末卷拆开看:常量、指针与函数三线并行的知识地图
很多人复习 C++ 程序设计基础,习惯从第一章语法顺着往下翻,翻到指针就卡住,翻到函数指针直接放弃。但把一份完整的期末 A 卷摊开逐题归类,会发现考点的分布其实高度集中:常量与表达式、流程控制、函数与重载、数组与指针、结构体与动态内存,五块内容撑起了 100 分里的绝大部分。换句话说,这门课不是知识点太多,而是几个核心机制反复换马甲出现。这份笔记就是按这套卷子的题型结构重新排布的一张复习地图:先看清五大模块各自考什么,再逐个拆解易错细节,最后落到一份可以照着走的查漏补缺清单。适合已经学过一遍、正在集中复习或准备补考的人,也适合想确认自己基础有没有漏洞的自学者。
2. 常量、运算符与表达式:选择题前五题的踩分逻辑
2.1 常量与变量名的边界在哪
卷子第一题问“哪个是不合法的常量”,四个选项里0xab是十六进制整型常量,"student"是字符串常量,618E3是科学计数法表示的浮点常量,而count只是一个标识符。这道题真正考的不是记忆,而是“常量必须有字面量形态”这一条判断标准。复习时把常量分成四类记:整型(十进制、八进制以 0 开头、十六进制以 0x 开头)、浮点(含小数点和指数形式)、字符(单引号,本质是整型)、字符串(双引号,末尾隐含\0)。容易混的是'a'和"a":前者是字符常量占 1 字节,后者是字符串常量占 2 字节。变量名则要满足标识符规则——字母或下划线开头,只含字母、数字、下划线,且不能是关键字。
2.2 自增自减与逻辑运算的求值顺序
第二题int a=1,b=1; --a && --b;是短路求值的经典考法。&&从左向右求值,左边--a先把 a 减到 0,结果为假,整个表达式已确定为假,右边--b根本不会执行。所以最终 a=0、b=1。这里有两个层次要分清:前置--先减再用,后置a--先用再减;而逻辑运算符的短路特性会让右侧的副作用“消失”。第四题问哪个表达式合法,++(a++)、a++++b、++a++b全部不合法,原因是自增运算符作用于变量而不是表达式结果,且++不能连续拼接。判断这类题只需一条:++/--的操作数必须是可修改的左值。
条件运算符的优先级也常被拿来设陷阱。第五题x>y ? x++ : y++,x=1、y=2,条件为假走y++,y 变为 3,x 不变,随后x+y得 4。注意条件运算符是右结合的,嵌套时从右往左结合,但优先级低于关系运算符、高于赋值运算符。
2.3 逻辑表达式的等价变形
第三题要求用逻辑表达式表示“大于 2 或小于 -2”。直接写是a>2 || a<-2,但选项里给的是!(a>=-2 && a<=2),这是德摩根律的变形:!(P && Q)等价于!P || !Q。把a>=-2 && a<=2取反,正好得到区间外的两种情况。复习时把三条等价关系背熟:!(P&&Q) = !P||!Q、!(P||Q) = !P&&!Q、!(a>b) = a<=b。这类题不要求你写出最简形式,只要求判断哪个选项与题意等价,所以逐项代入边界值验证最快——取 a=3 和 a=-3 各试一遍,能排除大部分错误选项。
提示:逻辑表达式题不要靠“读起来像”来选,代两个边界值进去算,比推公式稳。
3. 流程控制:循环、switch 与分支的隐藏陷阱
3.1 for 循环的三个表达式各管什么
第六题for (i=10; i=count; i--)里,中间的条件写成了赋值i=count而不是比较i==count。赋值表达式的值是赋完后的 i,只要 count 非零就恒为真,循环要么不执行要么死循环。这道题 count 初值为 1,i 被赋成 1 后条件为真,但循环体里 count 递减,下一轮 i 又被赋成新的 count,最终 count 减到 0 时条件为假退出——所以实际执行次数取决于 count 的递减节奏。这类题的核心是记住 for 的三个部分:初始化只执行一次,条件每轮先判断,增量在循环体之后执行。把i=count误读成i==count是最常见的翻车点。
第七题判断“哪个没有形成死循环”,要逐个分析循环变量的变化路径。while(a){a++;}中 a 从 10 开始一直增大,永不为 0,是死循环;do{...}while(i>=0)中 i 从 5 递减到 -1 时条件为假,正常退出;for(i=0;i=3;i++)条件恒为真,死循环;while(1)里靠break跳出,但i=i%10后 i 最大是 9,if(i>10)永远不成立,也是死循环。判断死循环的通用方法是:找出循环条件的变量,追踪它在循环体内是否单调趋向终止值。
3.2 switch 的穿透与 break 的位置
第八题switch(m)中 m=2,从case 2进入,输出"2",因为没有break,继续穿透执行default,再输出"default",最终屏幕上是2default。switch 的规则只有两条:从匹配的 case 标签开始顺序往下执行,遇到 break 才跳出;default 的位置不影响匹配顺序,只影响没有匹配时的入口。复习时把“穿透”当成默认行为、把 break 当成显式中断来记,就不会反着理解。另外 switch 的表达式必须是整型或枚举,case 标签必须是常量表达式,这两条在填空题里也常出现。
3.3 分支嵌套与 else 的配对
第十二题给了一段 if-else 链,问哪个程序段执行后 x 不等于 10。这类题的关键是 else 与最近的未配对 if 结合,以及多个独立 if 会依次判断、后面的可能覆盖前面的赋值。以选项 B 为例:if(a>b) x=a;不成立跳过;if(b>c) x=b;不成立跳过;if(a<c) x=10;成立,x 被赋 10。而选项 A 是 if-else if-else 结构,a>b 为假、a<b 为真,执行a=8而不是给 x 赋值,x 保持未初始化——这正是“x 不为 10”的那一项。做这类题先在草稿上画执行路径,标出每个分支是否进入,比心算可靠。
4. 函数、重载与函数指针:从原型到回调的完整链路
4.1 函数原型的合法性与默认参数
第九题问哪个函数原型有错,Func(int a,b,c);的问题在于形参列表里每个参数都必须单独声明类型,不能写成int a, b, c这种“类型只写一次”的形式。其余三项Func(int&, int*)、Func(int*, int*)、Func(int=1,int=2)都合法,其中第三项展示了默认参数:从右向左连续给默认值,调用时可以少传。默认参数还有一条硬规则——同一个参数的默认值只能指定一次,通常写在声明里而不是定义里,否则重定义会报错。
第十题const int MAX=1000; func(MAX)能正确执行,问 func 的原型。MAX 是 const 整型,传给int&会因不能把常量绑定到非 const 引用而失败;传给int*需要取地址,实参是值不是地址,也失败;只有const int&能接收常量实参。这条规则要记牢:const 对象只能绑定到 const 引用或按值传递,不能绑定到普通引用。
4.2 重载的判定标准
第十四题问哪个是正确的重载。重载的唯一标准是“同名函数、参数列表不同”,返回值类型不同不构成重载。选项 A 两个same(int,double)参数完全相同、仅返回值不同,是重复定义;选项 B 参数个数不同,构成重载;选项 C 两个版本只差默认参数值,参数列表实质相同,也是重复定义;选项 D 函数名不同,根本不是重载。判断时把每个函数的参数类型序列列出来对比,序列相同就是冲突,序列不同就是重载。默认参数不改变参数列表的“形状”,所以靠改默认值来“制造重载”是行不通的。
4.3 函数指针的声明与调用
第十三题int(*p)(int*,int)=sum;声明了一个函数指针 p 指向 sum。调用方式有四种写法:p(a,b)、(*p)(a,b)、sum(a,b)都正确,而(&p)(a,b)错在取的是函数指针变量本身的地址,类型变成“指向函数指针的指针”,不能直接当函数调用。函数指针的声明要抓住括号:int(*p)(int*,int)中*p先结合,说明 p 是指针,再往外看是“指向返回 int、参数为 (int*,int) 的函数的指针”。少了括号写成int *p(int*,int)就变成“返回 int* 的函数声明”,这是最经典的翻车点。
函数指针在填空题里还会以形参形式出现。卷子第三大题第 2 小题的梯形法求积分,trap的形参写成double (*fun)(double),调用时把f1、f2、f3作为实参传进去,循环里用(*fun)(a)求被积函数值。这段代码的骨架值得抄一遍:
// 梯形法求积分:fun 为函数指针,a、b 为区间端点,n 为等分数 double trap(double (*fun)(double), double a, double b, long n) { double t, h; int i; t = ((*fun)(a) + (*fun)(b)) / 2.0; // 两端点函数值取平均 h = (b - a) / n; // 步长 for (i = 1; i <= n - 1; i++) t += (*fun)(a + i * h); // 累加内部节点 t *= h; // 乘步长得积分近似值 return t; }参数说明:fun是函数指针,决定“积哪个函数”;a、b是积分上下限;n越大精度越高,卷子里取 10000。主函数里trap(f1,0,1,10000)求第一个积分,trap(f2,1,2,10000)求第二个,第三个sin的积分照同样格式补一行t3 = trap(f3,0,3.14159,10000);即可。函数指针的意义就在这里:同一套积分逻辑,换一个函数名就换一个被积函数,不用写三遍循环。
5. 数组、指针与字符串:地址运算的高频易错区
5.1 二维数组的地址表示
第十五题int a[2][2]={1,2,3,4};问哪个不能表示a[0][0]的地址。a[0]是第 0 行的首地址,类型int*,指向a[0][0];&a[0][0]直接取元素地址;*(a[0])对行首地址解引用得到a[0][0]的值,不是地址;*a对数组名解引用得到第 0 行,等价于a[0],是地址。所以不能表示地址的是*(a[0])。二维数组的地址体系要分层记:a是“行指针”,a[i]是“元素指针”,a[i][j]是元素值;a+i跳一行,a[i]+j跳一个元素。
第十九题int x[3][4], *p;问哪条赋值正确。p=x类型不匹配(x 是行指针);*p=x是给 p 指向的内容赋值,p 还没初始化;p=x[0][0]把整数赋给指针,类型错;p=*x中*x等价x[0],是int*,正确。这类题只考类型匹配,把每个表达式的类型写出来对照即可。
5.2 指针与数组名的等价与不等价
第十八题int Ary[5]={1,2,3,4,5}, *pAry=Ary;问哪个不能表示数组元素。*pAry是Ary[0];pAry[0]同样是Ary[0];pAry+1是地址不是元素;pAry[pAry-Ary]中pAry-Ary为 0,等价pAry[0]。所以不能表示元素的是pAry+1。这里要区分“地址”和“元素”:带*或下标运算才取到值,裸指针加偏移仍是地址。数组名在大多数表达式里退化为首元素地址,但它不是指针变量,不能被赋值、不能自增,Ary++是编译错误。
5.3 字符串长度与转义字符
第十六题char *str="\nThank\10you,\0sir! ";求strlen。strlen从首字符数到第一个\0为止,不包含\0。逐个字符拆:\n算 1 个,Thank5 个,\10是八进制转义算 1 个,you,4 个,接着就是\0,停止。合计 1+5+1+4=11。注意\10是八进制数 10(十进制 8),不是字符1和0两个字符;\0是字符串结束标志,后面的sir!不计入长度。这类题错在把转义序列拆成多个字符,或者忘了\0截断。
第十七题char *s[]={"Maths","C++","English","Chinese"}, **p; p=s;问cout<<p[2]输出什么。s 是字符指针数组,p 是二级指针指向 s 的首元素。p[2]等价*(p+2),取到 s[2],即指向"English"的指针,输出English。二级指针的偏移单位是“指针”,不是字符,这一点和一级指针偏移单位是元素类型要区分开。
5.4 结构体指针的成员访问
第二十题Person person[2]={{...},{...}}, *pPer=person;问哪个引用形式错误。person[1]->code错在person[1]是结构体对象不是指针,不能用->;pPer->code正确;person[1].code正确;(*pPer).code正确。规则很干脆:对象用.,指针用->,(*指针).成员与指针->成员等价。结构体数组名退化为指向首元素的指针,所以pPer可以指向person[0],pPer+1指向person[1]。
6. 易错点清单:五个最容易翻车的地方
易错点一:把赋值当比较。为什么漏:if(i=count)和if(i==count)只差一个等号,肉眼扫过去极易放过。怎么补:凡是条件表达式里出现单个=,先停下来确认是不是笔误;复习时把所有循环条件、if 条件单独抄一遍,逐个检查运算符。
易错点二:switch 忘记 break 导致穿透。为什么漏:写代码时只关注匹配的 case,忘了后续分支会继续执行。怎么补:把“每个 case 末尾默认加 break,除非明确要穿透”当成肌肉记忆;做题时在草稿上标出每个 case 的出口。
易错点三:const 实参传给非 const 引用。为什么漏:平时写函数习惯用int&接收参数,遇到常量实参才暴露问题。怎么补:记住“const 对象只能绑 const 引用或按值传”,函数设计时如果不需要修改实参,形参加 const 引用更安全。
易错点四:函数指针声明漏括号。为什么漏:int *p(int)和int (*p)(int)视觉差异小,语义天差地别。怎么补:看到函数指针先找括号,(*名字)是指针的标志;写完后用“p 是指针,指向函数”这句话复述一遍验证。
易错点五:strlen 把转义序列拆成多个字符。为什么漏:\10、\0这类八进制转义看起来像两个字符。怎么补:数长度前先把字符串按转义单元切开,每个\开头的序列算一个字符,遇到\0立即停止。
注意:这五条不是“知道就行”,而是要在做题时形成检查动作——每道选择题做完,用这五条过一遍,能拦下大部分非知识性失分。
7. 复习清单:按题型倒推的查漏补缺路线
复习到这一步,最有效的做法不是再从头翻书,而是拿一份卷子按题型倒推自己缺哪块。下面这张表把五大题型的考点、对应章节和自检动作列在一起,照着走一遍,漏洞基本能定位出来。
| 题型 | 主要考点 | 对应模块 | 自检动作 |
|---|---|---|---|
| 单项选择题 | 常量、运算符、流程控制、函数原型、指针 | 第 2~5 章 | 限时 20 分钟做完 20 题,错题按易错点归类 |
| 写出执行结果 | 循环嵌套、递归、switch、引用传参、结构体指针 | 第 3、4、5 章 | 手算每行输出,再上机验证,差异处重点看 |
| 填空补全 | 加密算法、函数指针、素数判断、排序 | 第 4、5 章 | 遮住答案自己填,填不出说明该语法点没掌握 |
| 编写函数 | 结构体数组找最值、动态数组逆置 | 第 5 章 | 不看参考代码独立写,编译通过后再对照 |
具体执行分三步。第一步,把第 2 章到第 5 章的易错点清单抄在一张纸上,做题时放在旁边,每错一题就在对应条目上画一笔,画得最多的那条就是你的薄弱环节。第二步,针对薄弱环节回到对应小节,把该节的代码示例手敲一遍——比如函数指针不熟,就把梯形法那段完整敲出来,改一改n的值看结果怎么变;动态数组不熟,就把逆置函数补全后跑几个不同长度。第三步,考前两天只做两件事:重做错题本上的题,以及把五个易错点默写一遍。
我自己的习惯是每次复习完一个模块,强制用“能不能不看书画出这个模块的地址/调用关系图”来验收——画不出来的地方就是没真懂的地方。指针那一章我画过三遍才把二级指针的偏移单位理顺。希望这份清单能帮你少走两遍弯路,把时间花在真正的漏洞上。
本文还有配套的精品资源,点击获取