☰
C++期末复习主线:表达式、控制流、函数与指针核心考点
2026/11/2 5:26:08 网站建设 项目流程

简介:这份资源是华南理工大学《C++程序设计基础》A卷期末试卷的PDF电子版,面向正在学习C++语法、准备课程考试或需要刷题巩固基础的高校学生。试卷为闭卷形式,满分100分、考试时间120分钟,共四大题,覆盖常量与变量、逻辑与自增运算符、条件与循环控制、switch语句、函数原型与重载、const引用、数组与指针、字符串及结构体等核心考点,选择题部分还配有逐题解析,便于对照理解易错点。包内共1个PDF文件,约288KB,内容为完整试卷与答案解析,可直接打印或在线查阅。已有116人学习,适合作为期末复习自测、课堂练习补充或教师出题参考,帮助读者在真实题型中检验语法掌握程度并查漏补缺。

1. 一张 C++ 基础卷的知识地图:从常量到指针的复习主线

C++ 程序设计基础的期末卷,看起来是 20 道选择题、6 道读程序题、15 个填空、2 道编程题,实际上它只考一条主线:表达式怎么算、控制流怎么走、函数怎么传、数组和指针怎么指。这条主线串起常量与变量、运算符优先级、逻辑短路、循环边界、switch 穿透、函数原型与重载、const 引用、数组退化、指针运算、结构体成员访问这些点。复习时如果按题号刷,很容易刷完就忘;按这条主线梳理,才能把「为什么这题选 C 不选 D」讲清楚。这份笔记适合正在系统学 C++ 基础、准备期末闭卷考试的人,也适合已经学过一遍、想快速查漏补缺的人。下面按知识模块逐块拆,最后落到一份能直接照着走的复习清单。

2. 表达式与常量:选择题前五题的踩坑重灾区

2.1 常量合法性判断:0xab、618E3 与 count 的区别

卷子第一题问「下列选项中不合法常量」,四个选项分别是0xab、"student"、618E3、count。判断常量合法性,先看字面量形态:0x开头是十六进制整型常量,双引号包起来是字符串常量,带E的指数形式是浮点常量,而count是一个标识符,没有字面量特征,所以它不可能是常量。这里最容易翻车的地方是把618E3当成非法,其实618E3等价于618×10³,是合法的浮点常量;反过来,0xab里的a、b是十六进制数码,不是变量名,也不能误判。

梳理下来会发现,常量题真正考的是「字面量的书写规则」,而不是「这个值能不能改」。复习时把整型(十进制、八进制0开头、十六进制0x开头)、浮点(小数形式、指数形式)、字符(单引号、转义)、字符串(双引号、末尾隐含\0)四类各记一个合法例子和一个非法例子,比背定义有效。

2.2 逻辑短路与自增自减:--a && --b到底执行几步

第二题int a=1,b=1; --a && --b;问执行后 a 和 b 的值。&&的规则是左操作数为假就不再算右边,--a先把 a 减到 0,0 为假,于是--b根本不执行,b 保持 1,答案是 a=0、b=1。很多人会顺手把两个都减了,选成 0 0,这就是没把「短路求值」当回事。

同一类坑还出现在自增自减的合法性上。第四题问哪个表达式正确,++(a++)、a++++b、++(++a)、++a++b里,a++的结果是右值,不能对它再取地址或再自增,所以++(a++)非法;a++++b会被切成a++ ++b,同样非法;++(++a)对++a的结果再自增,++a返回的是左值,语法上成立;++a++b则是++a和++b之间少了运算符,非法。这里的关键判断标准只有一条:前置自增返回左值,后置自增返回右值,右值不能再被自增。

2.3 条件运算符与逗号表达式的求值顺序

第五题x=1,y=2,表达式x>y? x++ : y++之后求x+y。条件运算符先判断x>y,1>2 为假,走y++,y 变成 3,x 不变仍是 1,所以x+y是 4。注意题目问的是「表达式x>y? x++:y++,x+y的值」,逗号在这里是分隔两个表达式,先算条件表达式再算x+y,顺序不能颠倒。如果先算x+y再算条件表达式,结果就变成 3,这是典型的读题顺序错误。

提示:条件运算符?:的优先级低于++、高于赋值和逗号,遇到混合表达式先按优先级加括号再算,别凭感觉。

3. 控制流三件套:循环边界、switch 穿透与 if 分支覆盖

3.1 for 循环条件写错一个等号,循环次数全变

第六题for (i=10; i=count; i--),条件是i=count而不是i==count,赋值表达式的值是赋进去的 count,count 初值为 1,非零为真,循环会一直执行,但循环体里count--让 count 变成 0,下一轮条件i=0为假,循环结束。所以实际执行次数取决于 count 什么时候被减到 0,这题的正确理解是「赋值当条件」导致循环次数由循环体改变 count 的速度决定,而不是简单的 1 次或无限次。复习时看到for条件里出现单个=,先标红,再顺着循环体看变量怎么变。

第七题问「没有形成死循环的是哪个」,四个选项分别考while(a)里 a 只增不减、do-while的i>=0边界、for(i=0;i=3;i++)的赋值条件、while(1)里i=i%10后if(i>10)break永远不成立。判断死循环看两点:循环变量有没有朝着让条件变假的方向走,以及 break 的条件有没有可能达到。B 选项i从 5 递减到 0 后条件i>=0仍为真,但下一轮i--变成 -1,条件变假,所以它不是死循环——这里最容易漏的是「递减到负数」这个边界。

3.2 switch 没有 break 的穿透效应

第八题m=2,switch(m)从case 2进入,输出"2",没有break,继续执行default,输出"default",最终屏幕上是2default。switch 的规则是「从匹配的 case 开始,一直往下执行,直到遇到 break 或 switch 结束」,default 的位置不影响穿透顺序,它只是「没匹配上时从这里进」。很多人以为 default 只在完全没匹配时才执行,忽略了它写在 case 后面时也会被穿透到。

注意:switch 的 case 标签必须是整型常量表达式,case 1.5、case x(x 是变量)都非法;穿透是有意为之还是漏写 break,读程序题里要按「没有 break 就继续走」硬算,不要替它补 break。

3.3 if-else 链与独立 if 的覆盖差异

第十二题给a=1,b=2,c=3,问哪段程序执行后 x 不为 10。A 是if(a>b) x=5; else if(a<b) a=8; else a=10;,注意它改的是 a 不是 x,x 始终没被赋值,所以 x 不为 10。B、C、D 都是若干独立 if 依次判断,只要有一条命中就把 x 赋成 10。这题考的是「else if 是一条链,只走一个分支」和「独立 if 每条都判断」的区别,以及「赋值对象是 x 还是 a」这种读题细节。复习时把每段代码的「最终被赋值的变量」圈出来,比逐行翻译更稳。

4. 函数与参数传递:原型、重载、const 引用与函数指针

4.1 函数原型合法性:默认参数只能从右往左给

第九题问哪个函数原型有错,Func(int a,b,c);里 b、c 没有类型,C++ 不允许这种省略,所以它错;Func(int&, int*)、Func(int*, int*)、Func(int=1,int=2)都合法。默认参数还有一条硬规则:一旦某个参数给了默认值,它右边所有参数都必须有默认值,所以Func(int=1, int)这种写法非法,而Func(int, int=2)合法。考试里常把这条规则藏在原型判断里,看到默认参数就从右往左扫一遍。

4.2 const 引用与 const 指针:func(MAX)能过编译的原型长什么样

第十题已知const int MAX=1000; cout<<func(MAX)能正确执行,问 func 原型。MAX是 const int,普通int&不能绑定 const 对象,int*也不能接一个 const int 的值,const int*需要取地址,而调用处传的是值不是地址,所以只有int func(const int&)能直接绑定。第十一题反过来,void func(const double&, int*),调用时第一个实参可以是PI*3、PI、3.14159这些右值或 const 值,第二个实参必须是int*,所以fun1(&PI,*x)里&PI是const double*、*x是 int 值不是指针,两个位置都错。

这两题合起来就是一条复习口诀:const 引用能接左值也能接右值,普通引用只能接左值;指针参数看实参是不是地址,const 指针看能不能把 const 对象的地址交出去。

4.3 函数指针调用与重载判定

第十三题int(*p)(int*,int)=sum;,问哪个不能正确调用 sum。p(a,b)、(*p)(a,b)、sum(a,b)都合法,(&p)(a,b)把「函数指针的地址」当函数调用,类型对不上,所以 A 错。函数指针的调用形式p(...)和(*p)(...)等价,&p是二级指针,不能直接当函数用。

第十四题问正确的重载,重载要求「同名、参数列表不同」。A 两个same(int,double)参数完全相同、返回类型不同,不构成重载;B 参数个数不同,构成重载;C 两个same(int,int=1)和same(int,int=3)参数列表看起来不同,但默认参数不参与重载区分,调用same(1)时两个都能匹配,产生二义性,所以不合法;D 函数名不同,根本不是重载。这里最容易错的是 C,以为默认值不同就算不同签名,实际上编译器只看参数类型列表,默认值只是调用时的填充。

// 合法重载:参数个数不同 int same(int a, double b); int same(int a, double b, int c); // 非法:仅返回类型不同,不构成重载 // int same(int, double); // double same(int, double); // 非法:默认参数导致调用二义 // int same(int, int = 1); // int same(int, int = 3);

上面代码里被注释掉的两组就是卷子里 A、C 选项的翻版,复习时把「返回类型不参与重载」「默认参数不参与重载区分」两句话写在便签上,比刷十道同类题管用。

5. 数组、指针与字符串:地址表示、退化与转义字符

5.1 二维数组元素地址的四种写法

第十五题int a[2][2]={1,2,3,4};问哪个不能表示a[0][0]的地址。a[0]是第一行的数组名,退化成int*,指向a[0][0];&a[0][0]直接取地址;*(a[0])对行首指针解引用得到a[0][0]的值,不是地址;*a对二维数组名解引用得到第一行,退化成int*,也是地址。所以 C 错在「解引用后拿到的是值不是地址」。二维数组的地址体系可以记成一张小表:

写法类型含义
aint(*)[2]指向第一行的指针
a[0]int*第一行首元素地址
&a[0][0]int*首元素地址
*aint*第一行首元素地址
*(a[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]。所以 C 错在把指针当成了元素。指针和下标的核心等价式是*(p+i) == p[i],p+i本身是指针,只有解引用或下标才是值。

第十九题int x[3][4], *p;问哪条语句正确。p=x类型是int(*)[4]赋给int*,不兼容;*p=x左边是 int 右边是二维数组名,不兼容;p=x[0][0]把 int 值赋给指针,不兼容;p=*x里*x是第一行,退化成int*,正确。这题和 5.1 的表是同一套知识,复习时把「二维数组名解引用一次得到行指针,行指针退化成元素指针」这句话吃透,两题一起过。

5.3 字符串长度与转义字符计数

第十六题char *str="\nThank\10you,\0sir! ";问strlen。strlen数到第一个\0为止,\n是一个字符,\10是八进制转义,表示一个字符(八进制 10 即十进制 8),\0是字符串结束符,后面的sir!不再计入。逐个数:\n(1) +T h a n k(5) +\10(1) +y o u ,(4) = 11,遇到\0停止,所以是 11。选项里给 20、16、12、11,正确答案是 11。这里最容易错的是把\10当成两个字符\1和0,或者把\0后面的内容也算进去。

第十七题char *s[]={"Maths","C++","English","Chinese"}, **p; p=s;问cout<<p[2]。p是二级指针,p[2]等价于*(p+2),取到的是s[2],即字符串"English"的首地址,cout输出字符串内容English。如果写成**p或*p[2]才是字符E。二级指针和字符串数组的组合,判断输出内容先看「取到的是指针还是字符」。

5.4 结构体成员访问的三种写法与一个非法写法

第二十题struct Person{...} person[2], *pPer=person;问哪个引用形式错误。person[1].code是数组元素用点访问,合法;pPer->code是结构体指针用箭头,合法;(*pPer).code先解引用再点访问,合法;person[1]->code左边是结构体对象不是指针,用箭头非法。结构体访问就三条:对象用.,指针用->,(*指针).成员等价于指针->成员,混用就翻车。

6. 易错点清单:读程序题里最容易翻车的五处

6.1 易错点一:循环里break和continue的作用范围

读程序题第 4 题switch嵌在for里,case 'o': cout<<'o'; continue;的continue作用于外层for,跳过本轮剩下的cout<<'#'<<endl;而case 'e'没有 break,会穿透到case 'i'输出ei再 break。为什么容易漏:把continue当成只影响 switch,实际上 switch 不是循环,continue直接找最近的循环。怎么补:读带 switch 的循环,先把每个 case 的「输出什么、有没有 break/continue、跳到哪里」列成三列表,再按字符逐个走。

6.2 易错点二:递归函数的输出顺序

第 3 题MysteryFun先递归再cout<<ch,所以输出是「倒序」的;输入stud.,字符依次处理后递归到.停止,回溯时从最后一个有效字符往前打印。为什么容易漏:习惯按「读一个打一个」的正序推。怎么补:在草稿上画调用栈,进入时标箭头向下,cout写在递归调用之后就在回溯时打,写在之前就在进入时打。

6.3 易错点三:do-while至少执行一次

第 2 题do{i++; j--; if(!(i%3)) break;}while(j>0);,i 从 0 开始,第一轮 i=1、j=4,i%3不为 0 不 break,条件 j>0 为真继续;第二轮 i=2、j=3;第三轮 i=3、j=2,i%3==0触发 break,输出 i=3、j=2。为什么容易漏:把do-while当成while先判条件,少算一轮。怎么补:看到do先无条件执行一次循环体,再判while。

6.4 易错点四:数组作形参后退化成指针

第 5 题void fun1(int[], int, double&)里sizeof(p)如果写在函数内,得到的是指针大小而不是数组大小,所以卷子里用sizeof(ary)/sizeof(int)是在main里算好再传。为什么容易漏:以为形参int[]还是数组。怎么补:记住「数组形参一律退化为指针,函数内拿不到原数组长度,长度必须另传」。

6.5 易错点五:结构体指针链的->连写

第 6 题Node a[]={{"China",a+1},{"France",a+2},{"USA",a}}; Node *p=a;输出p->s、p->q->s、p->q->q->s、p->q->q->q->s,依次是China、France、USA、China,因为q构成环。为什么容易漏:只跟一层就停,或者把a+1当成字符串。怎么补:把每个节点的s和q指向画成三行小表,顺着箭头走,环状结构走四步回到起点是正常现象。

7. 复习清单:从填空和编程题反推的查漏补缺路线

填空和编程题最能暴露「会不会真写」。第 1 题加密程序考的是「取位、变换、逆置」三步:k=n保存原数,while(k)逐位取k%10,m=m*10+(t+7)%10边算边逆置,k/=10推进。第 2 题梯形法考函数指针作形参:double trap(double(*fun)(double), double a, double b, long n),循环里累加(*fun)(a+i*h),最后乘h。第 3 题随机数去重考check里p[i]==num判重、素数判断里p[i]%j==0跳出。第 4 题结构体排序考new Employee[total]、Output(p,total)、all[j].salary>all[t].salary、i!=t四个空。两道编程题分别考「结构数组找最低分」和「动态数组逆置」,核心都是「遍历 + 比较/交换」。

按这份卷子的分布,复习优先级可以排成下面这张表:

模块卷面占比必须拿下的点常见失分
表达式与常量约 20 分短路、自增合法性、条件运算符把&&两边都算
控制流约 25 分循环边界、switch 穿透、if 链漏算 do-while 第一轮
函数约 25 分原型、重载、const 引用、函数指针默认参数当重载
数组指针字符串约 20 分地址表示、退化、转义计数*(a[0])当地址
结构体与编程约 10 分点/箭头、动态数组、排序交换person[1]->code

查漏补缺的具体做法:先合上卷子,把上面五行的「必须拿下的点」各写一句自己的话解释,写不出来的就是漏洞;再挑读程序题里错过的题,不看答案重推一遍执行过程,重点标出「哪一步开始和答案分叉」;最后把两道编程题的函数签名默写一遍,void searchMin(data*, int, data&)和void adverse(int*, int)这种带指针和引用的签名能默对,说明参数传递这一块真的过了。

我自己的习惯是每次考前把「短路、穿透、退化、const 绑定」四个词写在草稿纸角落,每做完一道相关题就在旁边打个勾,四个勾齐了才交卷。从那以后我每次复习 C++ 基础都强制走一遍「表达式→控制流→函数→指针→结构体」这条线,不再按题号跳着刷。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询