ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

C++笔试高频考点全解析:指针、引用与运算符陷阱

C++笔试高频考点全解析:指针、引用与运算符陷阱

简介:面向广州大学计算机专业C++课程的一份习题答案文档,系统覆盖变量、数据类型、运算符、控制结构、函数、数组、指针等基础知识点,并对选择题和表达式求解给出解析,适合正在学习C++入门课程的学生用于课后自测与复习巩固。压缩包为单个doc文档,共1个文件,大小约1.55MB,便于直接打开查阅和按章节索引。目前已有442人学习下载。文档以习题1的27道选择题及解答为主体,涵盖标识符合法性、进制常量、运算符优先级、逻辑表达式求值、指针与引用等典型考点,并配有数学表达式转C++算术表达式、逻辑表达式表示条件等综合练习,参考价值较集中。对于需要快速核对答案、理清C++易错点的学习者来说,这份材料能在期末备考或自学阶段提供明确指引,帮助高效查漏补缺。

1. 这门课的考点分布:为什么选择题总在引用和指针上翻车

看过这份C++答案的人应该都有一个共同感受:单选题看着都眼熟,一选就错。整份习题里最反直觉、也最容易被抽去当考题的,恰恰是第14到第17题那组指针和引用题——比如int i=10, *p=&i;问 p 的值是什么,很多人上来就选 10,正确答案却是变量 i 的地址。这就是这门课笔试的典型考法:不考你背没背概念,考你对「名访问、引用访问、间址访问」三种访问方式是否真的分得清。

要拿分,先摸清题型的分布规律。这份资源覆盖的是C++入门阶段最核心的五大模块:语法与词法(main函数、编译流程、标识符、常量)、运算符与表达式(优先级、自增自减、短路求值)、控制结构(if、switch、三种循环)、指针与引用、简单编程题。其中运算符与表达式模块的选择题密度最高,几乎占了三分之一的分值,是性价比最高的得分点;指针和引用则是拉开差距的区分点。下面按模块拆开讲,每章直接给出高频考点和真题的答法,照着练就行。

2. 语法与词法基础:main函数、编译、标识符与常量的高频选择题

这一章对应的是习题1里的第1到第12题,考点集中在C++程序的基本结构、编译流程、关键字识别、合法标识符判定,以及整型常量、浮点常量、字符常量的写法规则。题型以单选为主,偶尔会变成判断改错题,难度不大,但细节非常琐碎,是典型的「背了就会、不背就懵」的送分模块。

2.1 程序最小单元与编译流程:main函数为什么是唯一必选项

选择题第1题问「一个最简单的C++程序可以只有一个什么」,正确答案是 main 函数。这道题考的是C++程序的入口规则:无论程序里有没有库函数、自定义函数,操作系统都从 main 开始执行。同理,第2题问「源程序变成目标程序必须经过什么」,答案是编译,因为C++是编译型语言,源文件要经过编译器翻译成机器码。这两题几乎每年都出,答错的人多半是把编译和解释、汇编混在一起。

做题时可以记一条主线:源程序 → 编译 → 目标程序(.obj)→ 连接 → 可执行程序(.exe)。编译负责翻译语法,连接负责把库文件和目标文件拼在一起。题目如果问「溢出发生在哪个阶段」,本质上是在问错误产生的时机。第5题「溢出」属于运行错误,因为只有程序真正跑起来、数据超出类型范围时才会发生,编译阶段只检查语法,检查不出数值溢出。

2.2 关键字与合法标识符:一套判定模板走遍所有变体

第6、7题考的是关键字和标识符的区分。C++关键字是语言保留的、不能用作标识符的单词,比如 while、sizeof、case、extern、new。合法标识符要满足两条:只能由字母、数字、下划线组成,且不能以数字开头;不能和关键字重名。第7题的正确答案 _abc 就是典型的合法形式,new 是关键字不能用,π 不是 ASCII 字符不能用,带双引号的 "age" 是字符串常量不是标识符。

这类题的快速判断顺序是:先看首字符是不是数字,再看有没有非法字符(空格、引号、π 这类符号),最后确认不是关键字。三步走完直接出答案。实际考试还可能变形为「下列哪个是非法标识符」,套路完全相同。

2.3 八进制、十六进制、浮点常量与字符常量:格式细节决定对错

进制和常量的写法是另一个爱出细节题的地方。八进制整型常量必须以 0 开头,数字范围只能是 0~7,所以 015 合法、080 不合法(出现了 8)、0a0 不合法(a 不是八进制数字)、0x 开头的是十六进制不是八进制。第9题选 015 就是这个道理。

十六进制以 0x 开头,后面跟 0~9 和 a~f,0xg 错在 x 后面跟了 g,g 不是十六进制数字。浮点常量的考点在三处:e 前面必须有数字、e 后面必须是整数、小数点可以省略整数部分但不能两边什么都没有。第11题里 -1e3.5 错在指数是小数,e-5 错在 e 前面没有数字,5.0e(1+4) 错在指数不能是表达式。

字符常量和字符串常量是高频混淆点。字符常量用单引号、只能有一个字符,字符串用双引号。第12题里 '\101' 是合法的字符常量,因为反斜杠开头的是转义序列,\101 是八进制 ASCII 码,对应字符 A;"a" 是字符串不是字符,'name' 单引号里放了多个字符不合法。

2.4 这一模块的真题速答清单

题号考点正确答案一句话理由
第1题程序最小结构main函数程序必须有入口
第2题编译过程编译C++是编译型语言
第3题语句结束符分号简单语句以分号结束
第6题关键字识别sizeof/case/extern全是保留字
第7题合法标识符_abc下划线开头、无非法字符
第9题八进制常量0150开头且只含0~7
第10题十六进制常量0xgg不是合法数字
第11题浮点常量12.34/-1e+5/0.1E-12e前有数字且指数为整数
第12题字符常量'\101'转义序列合法

这个模块的复习策略就是背规则加刷题,不需要理解太深。把进制前缀、e 的用法、单双引号的区别各写一遍,选择题基本都能秒杀。

3. 运算符与表达式:优先级、短路、自增自减,选择题的主战场

如果说上一章是送分题,这一章就是决定能不能上 80 分的关键。习题1里第18到第28题全部围绕运算符展开,考点极其集中:优先级、自增自减、逻辑短路、复合赋值、条件表达式、逗号表达式。这部分题目最大的特点是「看起来能算,一算就错」,因为C++的求值规则和人的直觉经常不一致。

3.1 优先级记忆法:先背一个精简层级,再处理同级结合性

第18题问下列运算符中优先级最高的是哪个,*高于+,而<=、*=都很低,所以选*。第19题问优先级最低的,? :条件运算符是C++里优先级最低的运算符之一,低于!、&&、!=,所以选? :。

优先级不需要背完整的十几行表格,考试常考的层级可以压缩成一句话:括号 → 单目(!、++、--、取址&)→ 算术(* / + -)→ 关系(< <= > >=)→ 逻辑(&& 高于 ||)→ 赋值(=、+= 等)→ 条件 ?: → 逗号。注意赋值和条件运算符特别低,逗号最低。遇到混和表达式先按这个层级括起来,再从左往右算,正确率会高很多。

3.2 自增自减与最贪心匹配:i+++j 到底怎么拆

第20题i+++j的值为 3,因为C++词法分析遵循「最贪心匹配」原则:能多取一个字符就多取一个,所以i+++j被拆成(i++) + j,先取 i 的原值 1 参与加法,得到 3,然后 i 自增为 2。第21题++i+j是 4,因为前置自增先把 i 变成 2 再相加。第22题问下列哪个表达式正确,a+++b合法,拆成(a++)+b;++(a++)错在a++不能做前置自增的操作数;a++++b会拆成(a++)++ + b,而a++的结果不是左值,不能再次自增。

这类题的标准答题流程是:第一步用贪心规则拆 token,第二步判断参与运算的是原值还是自增后的值,第三步注意自增结果能不能继续作为操作数。第23题++i||--j&&++k考的是另一件事——短路求值。||左边++i让 i 变成 1,非零即为真,整个||表达式直接确定为真,右边--j和++k根本不会执行。所以表达式值为 1,j 和 k 保持不变。

第24题++x || ++y同理:x 先自增为 2,非零为真,||短路,y 不会被自增,保持 1。所以 x 是 2、y 是 1。这里特别容易错,很多人写出 y=2,就是因为没意识到逻辑运算符的短路规则。遇到这种题,先看左侧能否确定整个表达式的值,能确定就立刻停。

3.3 复合赋值、条件表达式与逗号表达式:按执行顺序推

第26题x += x -= x * x初看很吓人,实际上遵守「从右往左」的结合顺序:先算x -= x * x,即x = 5 - 25 = -20;再算x += (-20),即x = -20 + (-20) = -40。这类连续复合赋值题,关键是把每一个复合赋值还原成展开式,并时刻盯住 x 的当前值,而不是用最初的 5 代入每一步。

第27题a < b ? a : c < d ? c : d是条件运算符的右结合。先看内层c < d ? c : d,3<4 为真,结果是 3;外层a < b ? a : 3,1<2 为真,结果是 1。第28题(x = 4 * 5, x * 5), x + 25考逗号表达式,整个表达式的值是最后一个子表达式的结果,但前面的逗号表达式要真正执行。先x=20,再算x*5得 100(丢弃),最后x+25=45,结果为 45。

3.4 条件表达式的反直觉陷阱:1<x<5为什么错

第25题是整份习题里错误率最高的一题。数学表达式1<x<5在C++里不能直接写成1<x<5,因为C++会把1<x<5理解为(1<x)<5:先算1<x得到一个布尔值 0 或 1,再拿这个 0 或 1 去和 5 比较,结果恒为真,完全失去判断 x 是否在区间内的意义。正确写法是1<x && x<5,或者用等价的x==2||x==3||x==4。

这类题在面试里也常被拿来当陷阱题,答的时候要主动说出来:关系运算符不能连续比较,必须拆成两个独立比较再用逻辑运算符连接。这也是第1.3节「用逻辑表达式表示条件」那一整组题的通用思路。

3.5 课后表达式转换题:数学式改C++的标准流程

除了选择题,这一模块还有一类必练的笔试题:把数学表达式写成C++表达式。原文里六个式子覆盖了常见考点,答题模板如下:

// 1. 连分数 1/(1+1/(1+1/(x+y))) double r1 = 1.0 / (1 + 1.0 / (1 + 1.0 / (x + y))); // 2. 嵌套多项式 x{x[x(ax+b)+c]+d}+e double r2 = x * (x * (x * (a * x + b) + c) + d) + e; // 3. ln(1 + |(a+b)/(a-b)|^10) ,注意fabs和pow double r3 = log(1 + pow(fabs((a + b) / (a - b)), 10)); // 4. sqrt(1 + PI/2 * cos(48 * PI/180)) ,角度转弧度 double r4 = sqrt(1 + 3.14159 / 2 * cos(48 * 3.14159 / 180)); // 5. cot((1-x^2)/(1+x^2)) = cos/sin double r5 = cos((1 - x * x) / (1 + x * x)) / sin((1 - x * x) / (1 + x * x)); // 6. lg(a^2 + ab + b^2),以10为底的对数 double r6 = log10(a * a + a * b + b * b);

这类题有三条硬规则:除法必须写成浮点数除法,整数相除会直接截断;三角函数、对数、幂运算要用sin、cos、tan、log、log10、pow、fabs这些库函数;角度值要先转成弧度。只要照着这三条逐项翻译,基本不会丢分。

4. 控制结构与循环:if悬挂、switch穿透、循环次数判定全解析

这一章对应习题2的选择题和程序阅读题,分值占比同样很高。考点集中在 if-else 的匹配规则、switch 的穿透行为、三种循环的执行次数判断,以及 break、continue、goto 的使用场景。这是整份资源里「程序阅读题」最集中的模块,读程序写结果的能力从这里开始真正拉开差距。

4.1 if-else 悬挂与变量作用域:两个必考的编译级陷阱

习题2思考题第5题是一个经典案例:变量 a 定义在 if 语句体内部,编译时直接报'a' : undeclared identifier。很多人不理解为什么,因为变量定义是编译期行为,而 if-else 是运行期行为;变量说明要求编译时就分配好存储空间,放在语句体里意味着只有执行到那个分支才有定义,编译器无法在分支外识别它。正确做法是把int a;提到 if 之前,语句体里只做赋值。

另一个高频坑是 if-else 的悬挂匹配:else总是与最近的未匹配if结合。读嵌套 if 程序时,先把每个 else 往上找最近的 if,再逐层分析,不要被缩进格式误导。典型的程序阅读题会故意把缩进写得与真实匹配关系不一致,考的就是这个点。

4.2 switch 的穿透行为:case 只是入口标签

习题2选择题第3题,i=2,走case 2执行i--,i 变成 1;因为没有 break,继续穿透到case 3执行++i,i 变成 2;遇到 break 退出。很多人只算到 case 2 就停了,漏掉了穿透。第2.2节程序阅读第2题也是这样,外层 switch 的 case 0 结束后没有 break,直接进入 case 1 执行a++和b++,所以输出两行。

switch 的答题模板一句话:每个 case 分支执行完后,如果没有 break,就继续执行下一个 case 的语句,直到遇到 break 或整个 switch 结束。default 放在哪里都会按顺序执行,不是只到最后才生效。

4.3 三种循环的次数判定:先判断还是先执行

while 是先判断后执行,条件一开始为假就一次都不执行。do-while 是先执行后判断,至少执行一次。for 的三个表达式里,初始化只执行一次,条件判断在每次进入循环体之前,步进表达式在每次循环体结束之后。

习题2的几道程序阅读题集中考这个。第1题while( !x && i<3 ):初始 x=0、i=0,!x为真且i<3为真,进入循环;执行x++后 x=1,再判断时!x为假,整个条件为假,退出。所以只执行 1 次,选 d。

do-while 那道题正好相反:do { i--; } while( i != 1 );,i 从 3 开始,第一次循环 i 变 2,条件 2!=1 为真;第二次循环 i 变 1,条件 1!=1 为假退出,共 2 次。第4题i=4, j=1模拟一遍就很清楚。

for 循环判断次数的通用方法:先列出每一次循环前后变量的变化,再检查条件在哪一次循环开始时变假。第5题for( i=1, j=5; i<j; i++ ) { j--; },每次循环 i 加 1、j 减 1,循环结束时 i=3、j=3。这里特别要注意的是循环内 j-- 和循环步进 i++ 的执行顺序,先执行循环体再执行步进。

4.4 死循环、break 与 continue:读程序时容易忽略的边界

第7题选 b:do { ++k; } while( k>=0 );,k 非负就永远为真,是死循环。a 选项循环三次后 x=3 退出;c 选项 a 从 5 减到 0 退出;d 选项 i 从 3 减到 0 退出。这类题检验的是对循环结束条件的敏感度。

break 和 continue 的区别在程序阅读题里反复出现。break 直接结束整个循环;continue 跳过本次循环剩余语句,进入下一次循环的条件判断。第2.2节第3题while( i<=10 ) if( ++i % 3 != 1 ) continue; else cout << i;,i 从 1 开始,每次先自增再判断余数,只有余数为 1 时才输出,所以输出 4、7、10。

第7题那个三层循环嵌套的x=16,考的是 continue 只影响内层循环。每次内层循环 j 为奇数时跳过后面的 x++,注意外层的两次 x++ 不受影响。这类多层嵌套题,建议先写出内层循环的完整执行表,再累加外层变量。

4.5 编程题套路:排序、三角形、成绩转换的标准框架

习题2编程题有三道值得背框架。三数排序题,用三次比较交换即可:

#include <iostream> using namespace std; int main() { int a, b, c, t; cin >> a >> b >> c; // 每次比较后保证 a 是当前最小值,逐步完成升序排列 if (a > b) { t = a; a = b; b = t; } if (a > c) { t = a; a = c; c = t; } if (b > c) { t = b; b = c; c = t; } cout << a << " " << b << " " << c << endl; return 0; }

这段代码的核心是「每轮比较把最小的放到最前面」,三次比较两两交换即可完成三个数的排序。如果题目变成四个数,就继续追加if比较,模式相同。三角形判断题的优先级顺序要看清楚:先判断能否构成三角形(任意两边之和大于第三边),再依次判断等边、等腰、一般三角形,顺序反了会导致等腰三角形被等边条件提前输出。

百分制转五级分制,推荐的写法是整除 10 映射到 switch 分支:

switch (int(score) / 10) { case 10: case 9: grade = 'a'; break; case 8: grade = 'b'; break; case 7: grade = 'c'; break; case 6: grade = 'd'; break; default: grade = 'e'; break; }

用整除代替区间判断,避免多个 if 条件的边界错误,也把 0 到 59 分的情况合并进 default。这里有一个细节:int(score)是强制转换,先把浮点成绩截断成整数,再整除。如果题目要求 85 分以上输出 very good,就不能用这个方法,得回到 if-else 区间判断。

5. 指针、引用与 const:区分「值、地址、别名」就能拿满分的模块

这一章是整份答案里最难、也是最值得花时间的一章。习题1第13到第17题全部围绕指针和引用,思考题和验证程序更是把这部分拓展到了「三种访问方式」「const约束」「指针的指针」的深度。笔试和面试都爱从这里出题,因为它能直接检验学生有没有真正理解内存模型,而不是背了几个概念。

5.1 指针的三层拆解:定义、赋值、间址访问

指针的核心只有三句话:指针变量存的是地址;*p是取指针指向的变量的值;&a是取变量 a 的地址。第14题int i=10, *p=&i;里,p 的值是 i 的地址,不是 10;*p表示变量 i 的值。所以 a 选项「p 的值为 10」错误。

第15题int a=5, b=10, c; int *p1=&a, *p2=&b;,问哪条赋值语句不正确。p1 = a错在把整数值赋给指针变量,整型和指针类型不匹配。这类题的判断标准就一条:指针变量只能接收地址值或另一个同类型指针的值,不能直接接收普通整数值。*p2 = b是把 b 的值赋给 p2 指向的变量,也就是 b 自己赋给自己,合法;p2 = p1是把 p1 的地址值赋给 p2,合法。

第16题考引用:int &pa=a, &pb=b;,pb = pa等价于b = a,合法。&pb = a错在引用一旦绑定不能重新绑定,不能取引用的地址再赋值;pb = &pa是把地址赋给引用,类型不对;*pb = *pa错在引用不能直接用*解引用。记住一条:引用名在定义时绑定一个变量,之后所有对引用名的操作都直接作用于被绑定的变量。

5.2 引用与指针的四条对比:思考题的标准答法

课后思考题第3题专门问引用和指针的区别,面试也常拿这道题当口试题。答题框架按四条说清楚:

比较维度引用指针
是否占用独立空间不占,引用名是别名占独立内存空间存地址
能否改变绑定/指向定义后不能重新绑定可以改变指向
访问方式直接访问被绑定对象需要*间址访问
定义要求必须初始化绑定可以先定义后赋值

追问版本还会问「引用和指针哪个更安全」,标准回答是引用更安全,因为不存在空引用,使用引用不需要判断是否为空;指针可能悬空,使用前要判空。第16题的pb = pa就是典型的引用传值,实际效果等同于b = a。

5.3 const 的四种形态:指向常量的指针 vs 常量指针

课后思考题第5题考察 const 的不同组合。const int *p表示指向常量的指针,即不能通过 p 修改它指向的值,但 p 可以指向别的变量;int * const p是常量指针,即 p 本身不能修改,但它指向的值可以通过 p 修改;const int * const p两者都不能改。常引用const T &r = x;则是定义了一个不能通过它修改对象的引用,实参传给形参时保护数据不被意外改动。

这个知识点本身不会单独出一大道题,但会嵌在选择题和改错题里,比如问「下列哪个定义表示不能通过指针修改所指向的值」。答题时先看const修饰的是谁:*右边是 const,说明指针本身不可变;*左边是 const,说明所指对象不可变。

5.4 交换变量的经典陷阱与程序阅读题

第13题问哪组语句不能交换 a 和 b 的值。d 选项a=b; b=a;执行后 a 和 b 都变成原来 b 的值,交换失败。b 选项的加减法交换a=a+b; b=a-b; a=a-b;能成功,但注意如果 a 和 b 是浮点数或数值很大时可能溢出。面试里追问「加减法交换的缺点是什么」,答溢出风险,所以常规交换还是用临时变量。

第17题是引用做交换的阅读理解:ra和rb分别绑定 a 和 b,三条赋值语句实际交换的是 a 和 b 的值,所以 a=3、b=5。第1.4节的第三道程序题考了流格式控制:

int a = 123; int &ra = a; int *pa = &a; cout << setw(5) << dec << a << setw(5) << oct << ra << setw(5) << hex << *pa << endl;

dec、oct、hex分别把输出切换为十进制、八进制、十六进制。123 的十进制是 123,八进制是 173,十六进制是 7b,所以输出结果是三列对齐的 123、173、7b。注意格式控制符有记忆效应,设置之后会一直影响后续输出,直到被新的格式控制符改变。

5.5 编程验证题:名访问、引用访问、间址访问

课后题第2和第4题都要求写验证程序,这类题在笔试里出现频率很高。完整的验证程序可以直接背下来:

#include <iostream> using namespace std; int main() { int a; cin >> a; a = a + 5; // 方式一:名访问,直接用变量名 int *pa = &a; // 指针指向 a cout << *pa << endl; // 方式二:间址访问,通过指针解引用 int &ra = a; // ra 是 a 的引用 cout << ra << endl; // 方式三:引用访问,相当于用别名 cout << &a << endl; // 输出地址,验证三种方式操作的是同一对象 return 0; }

答题时按三行分别说明:名访问是a=a+5这类直接操作;间址访问是声明指针后用*pa取对象;引用访问是声明int &ra=a后用别名操作。最后加上输出地址&a,验证三种方式指向的是同一个内存单元,这一分就稳了。

6. 常见失分点:五类必踩的坑与答题避错模板

把这份答案里所有题目过一遍,失分几乎都集中在五个固定模式上。这些不是概念没背熟,而是C++语法行为和直觉不一致导致的系统性错误。下面按「错在哪 → 为什么错 → 怎么答对」逐一拆开,考前过一遍能少丢不少分。

失分点一:if 判断写成赋值。习题2思考题第6题,输入 4 和 9,输出「9等于9」,因为判断语句写成了if( a=b )而不是if( a==b )。赋值表达式的值是被赋的值,9 非零即为真,所以永远走等于分支。怎么答对:遇到判断相等,先检查是==还是=;如果看到选项里出现if(x=y)这种写法,直接判定为逻辑错误,因为它合法但行为完全错误。

失分点二:变量定义放进了语句体。思考题第5题把int a=1;写在 if 分支内,编译报undeclared identifier。原因是变量定义在编译期就要分配空间,if 是运行期结构,分支不执行就没有这个变量。怎么答对:变量定义一律放在函数开头或块的最前面,if、switch、循环体内部只做赋值。

失分点三:switch 漏 break,穿透到下一个 case。选择题第3题,i 从 2 开始执行i--后变成 1,没有 break 继续执行 case 3 的++i变成 2。这类题必须把穿透当成默认行为来算,看到 case 结束没有 break 就要继续往下走,直到遇到 break 或 switch 结束。

失分点四:逻辑短路导致后半段不执行。++i||--j&&++k这类题,只要左侧已经能确定整体为真,右侧整个不执行。怎么答对:先看||左侧,非零直接结束;看&&左侧,为零直接结束。结束时另一侧的所有自增自减都不发生,变量值保持原样。

失分点五:进制和常量的边界规则记混。八进制出现 8 或 9、十六进制出现 g、浮点数 e 后面跟小数、字符常量用双引号,每一条都是送命题。怎么答对:考前花十分钟默写一遍规则,八进制 0~7、十六进制 0~9 加 a~f、float 指数必须整数、字符单引号字符串双引号。

我自己备考时吃过最大的亏就是第一种失分点,那时候读程序题看到if(a=b)直接当成a==b算,连错三道题。从那以后我每次做完选择填空都会专门回头扫一遍所有判断条件,确认没有把赋值当比较。这份答案的价值不在于背答案,而是把每一个错误都当成一个考点标本——你把错误的原因说清楚了,考场上就不会再犯。希望帮到你。

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

返回列表