GESP C++ 一级考级讲义:程序设计基础与规范
第一部分:计算机科学基础与编程环境
在程序设计与算法竞赛中,理解计算底层的硬件逻辑与运行机制是编写高效代码、分析算法空间与时间复杂度的基础。
1. 计算机历史与体系结构
- 早期通用电子计算机:ENIAC(埃尼阿克)于 1946 年 诞生于美国。其内部核心计算控制部分主要由电子管组成。
- 冯·诺依曼体系结构:现代计算机硬件系统设计的基石。其核心特性为“程序存储与程序控制”,硬件由五大基本部件组成:
- 运算器 (ALU):执行所有的算术运算与逻辑运算。
- 控制器 (CU):负责解析指令、控制数据流向。
- 存储器 (Memory):用于存放程序代码与数据。
- 输入设备 (Input Devices):向计算机系统输入数据,如键盘、鼠标、传感器等。
- 输出设备 (Output Devices):向外界呈现计算结果,如显示器、打印机、音箱等。
- 图灵奖 (Turing Award):计算机科学领域的最高荣誉,专门用于纪念英国数学家、计算机科学家艾伦·图灵(Alan Turing)。
2. 硬件组件分类与存储单位
- 输入设备与传感器:传感器能将外部物理信号(如温度、湿度)转换为电信号并输入计算机,在系统结构中扮演输入设备的角色。
- 存储单元及其换算:
- 计算机中用于度量存储空间容量的基本单位是字节(Byte,通常用大写字母 B 表示)。
- 二进制信息存储的最小单位是位(Bit,通常用小写字母 b 表示)。
- 换算关系:$1 \text{ Byte} = 8 \text{ Bit}$。
- 存储容量采用二进制倍数定义:$1 \text{ KB} = 1024 \text{ B}$,$1 \text{ MB} = 1024 \text{ KB}$,$1 \text{ GB} = 1024 \text{ MB}$。
3. 操作系统与编译环境
- 操作系统 (OS):管理计算机硬件与软件资源的底层系统软件。例如 Windows、Linux、macOS 以及鸿蒙(HarmonyOS)。
- 应用软件:运行在操作系统之上的单一功能软件,例如高德地图、腾讯会议、图像处理软件等。
- 集成开发环境 (IDE):提供程序编写、编译、调试一站式服务的工具软件。例如 Dev-C++。需要注意,Dev-C++ 是 IDE,而不是操作系统。
- C++ 源文件到可执行文件的构建生命周期: $$\text{C++ 源代码 (.cpp)} \longrightarrow \text{预处理} \longrightarrow \text{编译 (汇编代码)} \longrightarrow \text{汇编 (机器码目标文件 .obj)} \longrightarrow \text{链接} \longrightarrow \text{可执行程序 (.exe)}$$
- 注释的行为:程序中书写的单行注释
//或多行注释/* ... */主要用于提高代码可读性。在预处理阶段,注释会被编译器过滤清除,因此注释的多少绝对不会影响程序的运行效率。
第二部分:变量定义、标识符规范与基本数据类型
1. 标识符命名规范与关键字
标识符(变量名、函数名等)的命名必须严格遵守 C++ 语法的词法规则:
1. 字符集限制:只能由大小写字母、数字和下划线(_)组成。
2. 首字符限制:必须以大小写字母或下划线开头,不能以数字开头。
3. 保留字限制:不能使用 C++ 的关键字(如 int, for, do, if, false 等)。
4. 大小写敏感:C++ 语言严格区分大小写(例如 XingMing 与 xingming 是两个独立的标识符)。
- 常见标识符规则判定:
five_star(合法),_fiveStar(合法)。five-star(非法,含有减号-),0x321(非法,以数字开头)。cout(技术上可作为标识符,但属于标准库命名空间对象,覆盖其定义会导致标准 I/O 无法正常使用,实际编写时不推荐)。
2. 基本数据类型
C++ 在编译时需要确定变量的数据类型,以分配对应大小的物理内存:
* 整型 (int):在 32 位及以上硬件系统中通常占用 $4$ 字节空间,用于存储带符号整数。
* 短整型 (short):通常占用 $2$ 字节空间。
* 单精度浮点型 (float):占用 $4$ 字节。
* 双精度浮点型 (double):占用 $8$ 字节。在 C++ 中,无特殊后缀的小数字面量(如 7.0)默认解析为 double 类型。
* 字符型 (char):占用 $1$ 字节,用于存储单字符(ASCII 码)。字面量必须使用单引号约束。如 'A',其对应的十进制 ASCII 值为 $65$。
* 字面量差异判定:3 是一个整型常量(占 $4$ 字节),而 '3' 是一个字符常量(占 $1$ 字节,对应 ASCII 码值 $51$)。
* 布尔型 (bool):占用 $1$ 字节,逻辑值仅能为真(true,非 $0$ 值转化后为 $1$)或假(false,对应 $0$)。
3. 字面量的进制表示
在 C++ 中,整型字面量可以通过特定前缀改变其进位制:
* 十进制:无前缀,如 100。
* 八进制:以数字 0 开头。例如,010 代表八进制数,转换为十进制的值为 $8$。
* 十六进制:以 0x 或 0X 开头,如 0x10 转换为十进制为 $16$。
第三部分:基本运算符、表达式优先级与隐式类型转换
1. 算术运算符与整除陷阱
- 算术运算符:
+、-、*、/、%。 - 整除逻辑:当两个操作数皆为整型(
int)时,除法运算/执行向下截断整除,即舍弃余数部分。 - 例:
9 / 4结果为2;37 / 4结果为9。 - 要想保留小数,必须使表达式中的一个操作数转换为浮点数。例如:
a / 4.0。 - 取模运算符 (
%):求两个整数相除的余数。其两个操作数必须均为整型,若对浮点数进行取模运算(如2.5 % 2),编译将报错。 - 例:
10 % 3结果为1。
2. 自增自减与复合赋值
- 前置自增 (
++x) 与后置自增 (x++): ++x:先使变量x增加 $1$,然后返回增加后的变量(可作为左值)。x++:先返回变量x当前的值(作为右值),然后再使变量x自增 $1$。- 复合赋值运算符:
+=、-=、*=、/=、%=。例如a *= 3等价于a = a * 3。
3. 关系与逻辑运算符
- 关系运算符:
<、<=、>、>=、==、!=。结果为布尔型(真为1,假为0)。 - 数学关系连写陷阱:在数学中表示 $1 < x < 5$,在 C++ 中直接写入
1 < x < 5。- 求值流程:首先计算
1 < x,其结果为bool(真为 $1$,假为 $0$)。接着计算(0 或 1) < 5,该式恒成立。 - 正确表达式:必须使用逻辑与组合:
1 < x && x < 5。
- 求值流程:首先计算
- 逻辑运算符:
&&(逻辑与,双真为真)、||(逻辑或,单真为真)、!(逻辑非,单目,取反)。 - 逻辑运算符短路求值特性:
- 对于
A && B,若A评估为假,则系统直接返回假,不再执行/求值B。 - 对于
A || B,若A评估为真,则系统直接返回真,不再执行/求值B。
4. 运算符优先级与结合性
C++ 运算符优先级整体遵循以下规则(从高到低): $$\text{括号 ()} \longrightarrow \text{单目运算符 (!, ++, --, -)} \longrightarrow \text{算术乘除/取模 (, /, \%)} \longrightarrow \text{算术加减 (+, -)} \longrightarrow \text{关系比较 (<, >, <=, >=)} \longrightarrow \text{相等比较 (==, !=)} \longrightarrow \text{逻辑与 (\&\&)} \longrightarrow \text{逻辑或 (||)} \longrightarrow \text{三目运算符 (?:)} \longrightarrow \text{赋值与复合赋值 (=, +=, =)} \longrightarrow \text{逗号表达式 (,)}$$
5. 隐式类型转换与显式类型转换
- 隐式类型提升:当低精度数据(如
bool,char)与高精度数据(如int,double)混合运算时,低精度会自动转换为表达式中最高精度的类型后再进行计算。 - 例:对于表达式
((3 == 0) + 'A' + 1 + 3.0)(3 == 0)结果为false,隐式转换为整型0。'A'的 ASCII 码为65,转换为整型。- 表达式进行整型加法得到
66。 - 随后与浮点常数
3.0进行计算,整型66隐式提升为双精度浮点型66.0,最终求得值69.0,表达式的结果类型为 double。
- 显式类型转换(强制转换):
- C 风格语法:
(char)66。 - C++ 风格语法:
char(66)。 - 语法错误例:
char 66(缺少括号,语法错误)。
第四部分:控制流结构(分支与循环控制)
C++ 程序通过顺序、分支和循环三种控制结构来实现任何逻辑: * 顺序结构:程序按照代码的书写顺序,从上到下逐行不漏地执行。 * 选择(分支)结构:根据条件的评估结果,选择执行不同路径的代码块。 * 循环结构:在循环条件的约束下,重复执行特定的代码块。
顺序结构 分支结构 循环结构
┌─────┐ ┌──────┐ ┌──────┐
│语句1│ │条件 A│ ┌─┤条件 A│◀──┐
└──┬──┘ └──┬───┘ │ └──┬───┘ │
▼ ┌──┴──┐ │ ▼ 真 │
┌─────┐ 真 │ │ 假 │ ┌──────┐ │
│语句2│ ┌─────▼─┐ ┌─▼─────┐ │ │循环体│ │
└─────┘ │代码块1│ │代码块2│ │ └──┬───┘ │
└─────┬─┘ └─┬─────┘ │ └───┬───┘
└───┬─┘ │ 假 │
▼ └────────┼──▶
▼
1. 分支结构(if-else 与 switch-case)
if语句:- 括号内的表达式评估结果不一定是
bool类型。任何非零值会被隐式转换为真,零值会被隐式转换为假。 - 配对规则:
else子句不能独立存在,它总是与在同一作用域内最近的且未配对的if配对。 switch语句:case标签后面的表达式必须是整型常量表达式(包括char,bool)。- 穿透效应 (Fall-through):每个
case代码块末尾若没有显式写入break;语句,执行完该分支后,程序会无条件“穿透”到下一个case或default块中继续执行。
2. 循环结构(for、while、do-while)
for循环:格式为for (初始化表达式; 循环条件; 步进表达式)。- 如果在首次计算循环条件时结果就为假,则循环体一次也不会执行。
while循环:格式为while (循环条件)。适合用于循环次数不确定的场景(如按位拆分、辗转相除)。do-while循环:格式为do { 循环体 } while (循环条件);。由于其评估时机处于循环体执行之后,因此循环体至少会执行一次。- 死循环(无限循环)的特征:
- 省略
for循环条件:for (;;)。 - 条件恒为真:
while (1)或while (true)。
3. 循环辅助控制语句
break语句:立即终止并跳出当前层次的循环体(或switch块),执行紧随循环体后面的首行代码。continue语句:立即跳过本次循环迭代中剩余的语句,直接跳转到条件测试部分(在for循环中,跳转到步进表达式),准备进行下一次迭代。
第五部分:格式化与流式输入输出
1. 流式输入输出:cin 与 cout
- 流提取运算符
cin >> x的解析特性: - 输入流在处理数值读取时,会以空白字符(空格、换行、制表符)作为分隔符,或者在遇到首个非数字字符时停止读取。
- 例:
cpp int i; cin >> i; // 键盘输入为 "5+2"cin会正常读取数字5,在遇到+这一非数字字符时中断读取,将其留于输入缓冲区。变量i的最终值为5,程序不会报错。 - 逗号运算符输出陷阱:
- 若执行:
cout << (2, 3, "23"); - 括号内使用的是逗号表达式,其计算逻辑是依次求值各子表达式,并返回最后一项的值。因此,上式最终输出结果仅为字符串
"23"。
2. 格式化输入输出:scanf 与 printf
- 格式化占位符规范:
%d:带符号的十进制整型。%f/%lf:单/双精度浮点型。%c:单字符。- 输出对齐与前导零控制:
%5d:右对齐,输出位宽至少为 $5$。不足 $5$ 位时在左边补充空格。%-5d:左对齐,输出位宽至少为 $5$。不足 $5$ 位时在右边补充空格。%05d:右对齐,输出位宽至少为 $5$。不足 $5$ 位时在左边填充前导零'0'。%g:根据数值大小,自动选择输出%f或科学计数法形式,且不输出无意义的后缀零。- 例:
printf("__ %02d%2d$$", 3, 22);由于%02d使得整型常数3格式化为前导零补齐的两位"03",而%2d输出22的宽度已足,因此输出最终为"__ 0322$$"。
练习题集(本题集题目均提取自 GESP 一级历年真题及样卷)
一、单项选择题
Q1 (id: 3615)
以下不属于计算机输入设备的有( )。
A. 键盘
B. 音箱
C. 鼠标
D. 传感器
Q2 (id: 3616)
计算机系统中存储的基本单位用 B 来表示,它代表的是( )。
A. Byte
B. Block
C. Bulk
D. Bit
Q3 (id: 3617)
常量 7.0 的数据类型是()。
A. double
B. float
C. void
D. int
Q4 (id: 3619)
以下不可以作为 C++标识符的是()。
A. x321
B. 0x321
C. x321_
D. _x321
Q5 (id: 3620)
以下哪个不是 C++语言的关键字?
A. int
B. for
C. do
D. cout
Q6 (id: 3621)
如果 a、b 和 c 都是 int 类型的变量,下列哪个语句不符合 C++语法?
A. c = a + b;
B. c += a + b;
C. c = a = b;
D. c = a ++ b;
Q7 (id: 3622)
如果用两个 int 类型的变量 a 和 b 分别表达长方形的长和宽,则下列哪个表达式不能用来计算长方形的周长?
A. a + b * 2
B. 2 * a + 2 * b
C. a + b + a + b
D. b + a * 2 + b
Q8 (id: 3623)
表达式 ((3 == 0) + 'A' + 1 + 3.0) 的结果类型为()。
A. double
B. int
C. char
D. bool
Q9 (id: 3625)
如果 a 和 b 均为 int 类型的变量,下列表达式不能正确判断“a 等于 0 且 b 等于 0”的是()
A. (a == 0) && (b == 0)
B. (a == b == 0)
C. (!a) && (!b)
D. (a == 0) + (b == 0) == 2
Q10 (id: 3627)
在下列代码的横线处填写(),可以使得输出是 “20 10”。
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 20;
a = _______;// 在此处填入代码
b = a / 100;
a = a % 100;
cout << a << " " << b << endl;
return 0;
}
A. a + b
B. (a + b) * 100
C. b * 100 + a
D. a * 100 + b
Q11 (id: 3628)
在下列代码的横线处填写(),可以使得输出是“1248”。
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 8; ______) // 在此处填入代码
cout << i;
return 0;
}
A. i++
B. i *= 2
C. i += 2
D. i * 2
Q12 (id: 4572)
以下不是无限循环的语句为()
A. for(y=0,x=1;x>++y;x=i++) i=x
B. for(;;x++=i);
C. while(1){ x++; }
D. for(i=10;;i--) sum+=i;
Q13 (id: 11320)
对整型变量 i ,执行 C++语句 cin >> i, cout << i 时如果输入 5+2 ,下述说法正确的是( )。
A. 将输出整数 7
B. 将输出 5
C. 语句执行将报错,输入表达式不能作为输出的参数
D. 语句能执行,但输出内容不确定
二、判断题
Q14 (id: 3648)
程序员用 C、C++、Python、Scratch 等编写的程序能在 CPU 上直接执行。( )
Q15 (id: 3649)
在 C++语言中,注释不宜写得过多,否则会使得程序运行速度变慢。( )
Q16 (id: 3652)
if 语句中的条件表达式的结果必须为 bool 类型。( )
Q17 (id: 3653)
for 语句的循环体至少会执行一次。( )
Q18 (id: 4729)
字符常量的长度肯定为1。( )
Q19 (id: 4780)
bool类型的结果不是0就是1。( )
Q20 (id: 4781)
整形变量a赋值给浮点类型变量,值的大小不会变。( )
Q21 (id: 5377)
在 C++语言中,计算结果必须存储 in 变量中才能输出。( )
Q22 (id: 9783)
小杨最近在准备考 GESP,他用的 Dev C++来练习和运行程序,所以 Dev C++也是一个小型操作系统。( )
Q23 (id: 11072)
任何一个 for 循环都可以转化为等价的 while 循环。( )
练习题参考答案与深度解析(题目与答案独立呈现)
一、单项选择题答案与解析
Q1 【答案】B
- 解析:输入设备是指外界向计算机内部传递信息的物理组件。键盘、鼠标、传感器均属于向计算机输入状态或数据的输入设备。音箱是计算机用来向外界播放物理音频的设备,属于计算机系统结构中的输出设备 [3615]。
Q2 【答案】A
- 解析:计算机中表示物理存储空间容量的基本单位是字节,英文对应 Byte(大写字母 B 表示)。二进制信息的物理最小存储单位是二进制位,即 Bit(小写字母 b 表示) [3616]。
Q3 【答案】A
- 解析:在 C++ 基本数据类型系统中,不带后缀的小数常数字面量(如
7.0)默认解析为 double(双精度浮点型)数据。若要显式修饰为float类型,应书写为7.0f[3617]。
Q4 【答案】B
- 解析:根据 C++ 语法词法规则,标识符不能以数字开头。选项 B 中的
0x321是以数字0开头,所以无法通过编译阶段,不属于合法 C++ 标识符 [3619]。
Q5 【答案】D
- 解析:
int、for、do是 C++ 语法标准内置的语言核心关键字 [3620]。cout是标准库std命名空间中的预定义输出流对象,它在语法分类上并不是关键字。
Q6 【答案】D
- 解析:自增自减是一元单目运算符。语句
c = a ++ b;中,变量a后的自增++无法与后面的变量b直接进行语法组合,缺少算术二元运算符(如+、-),不符合 C++ 语法规范,会抛出编译错误 [3621]。
Q7 【答案】A
- 解析:根据运算符运算优先级,算术乘法优先于算术加法。选项 A 中的表达式
a + b * 2会被求值解析为:$a + (b \times 2)$,无法正确求出长方形的周长 $2(a+b)$ [3622]。
Q8 【答案】A
- 解析:此题考察 C++ 混合运算表达式的隐式类型提升逻辑。子表达式
(3 == 0)结果为bool型,字符型常量'A'、整型常量1以及双精度浮点型常数3.0相加时,类型自动提升至高精度上限,即 double 类型 [3623]。
Q9 【答案】B
- 解析:选项 B 表达式
(a == b == 0)的执行逻辑是自左向右结合: - 首先求值
a == b,若相等返回true(1),否则返回false(0)。 - 随后再用返回的 $0$ 或 $1$ 与后面的 $0$ 进行相等判断:
0 == 0(结果为真)或1 == 0(结果为假)。所以,只有在变量a与b不相等时,该表达式评估结果才为真。无法用来正确表达并判断“a等于0且b等于0”这一逻辑。 - 其他选项中:A 选项利用逻辑与关系;C 选项通过逻辑非取反,由于非零即真、零即假,
!a && !b即要求两个变量同为零;D 选项中,判断式等于 0 对应假(0)、等于 1 对应真(1),若两个关系式皆满足,相加结果刚好为 2 [3625]。
Q10 【答案】D
- 解析:本题采用干代码反推逆向工程解析:
- 程序最终输出结果是
20 10,代表最终状态时a为20、b为10。 - 根据第 7 行
a = a % 100;,由于它未变更变量b,说明第 7 行运行前变量a的值对 100 取模余数为20。 - 根据第 6 行
b = a / 100;,由于它未变更变量a,说明第 6 行运行前变量a的值对 100 的整除商是10。 - 结合上述两个判定,第 6 行执行前,变量
a的状态值应刚好为1020。 - 初始状态
a = 10, b = 20,代入各选项,只有 D 选项a * 100 + b(即10 * 100 + 20)在赋值给a后,其值刚好为1020[3627]。
Q11 【答案】B
- 解析:程序拟定输出序列为非线性增长的幂级数:
1、2、4、8。初始时循环自i = 1开始迭代,每次循环输出变量i,每次迭代更新时i乘上 2 并写回。所以,步进条件处最合适的写法是乘等复合赋值i *= 2[3628]。
Q12 【答案】A
- 解析:
- A 选项中,首轮迭代评估:初始化
y = 0, x = 1,条件部分为x > ++y。先对y进行前置自增,其值变为1,然后表达式等价于1 > 1。评估结果为假(false),控制流直接跳出循环体,不构成无限循环。 - B、D 选项省略了中间的循环条件测试语句,C++ 语法规定其默认效果恒为真,直接引发死循环。
- C 选项
while(1)条件恒为真,且循环体内未见任何退出控制(如break),形成死循环 [4572]。
Q13 【答案】B
- 解析:
cin标准输入流在处理整型变量读取时,遇到非数值字符(即+)会自动中断读取,并将未读取部分保存在缓冲区内。因此,对于输入字符串5+2,整型变量i仅成功提取并接收了整型数值5,输出结果即为5[11320]。
二、判断题答案与解析
Q14 【答案】错
- 解析:C、C++ 等高级程序设计语言编写的文本源代码无法被物理 CPU 直接运行,必须通过编译器和链接器进行处理,转换、生成对应的低级指令集(机器语言目标代码)后,才能交给 CPU 直接加载并执行 [3648]。
Q15 【答案】错
- 解析:源程序文件中的 C++ 语法注释仅对程序员及代码审查者可见,其作用是协助提高程序易读性。在编译器前端构建的预处理阶段,所有的注释都会被彻底过滤掉,不产生任何对应的汇编机器指令,所以注释多绝不影响程序的运行执行速度 [3649]。
Q16 【答案】错
- 解析:C++ 中的分支语句
if (表达式)对括号内条件的要求十分宽泛,并不强制限定为bool类型。任何整型或浮点表达式的评估值都可以参与条件评估:若其结果值为非零,系统自动隐式转换为逻辑真;若结果值为零,则隐式转为逻辑假 [3652]。
Q17 【答案】错
- 解析:
for循环是前置测试型循环。如果在首轮开始执行时,其初始化后的状态不满足循环控制条件(如for (int i = 0; i < 0; i++)),循环体代码将一次也不会被执行,直接跳过 [3653]。
Q18 【答案】对
- 解析:在 C++ 中,单引号定义的字符字面量对应单个独立的 ASCII 码字符。每个字符在物理内存中固定占用占 1 个字节的大小,所以字符常量的存储长度始终为 1 [4729]。
Q19 【答案】对
- 解析:在 C++ 语言中,布尔类型变量的值只有真和假。在与算术等类型隐式转换并输出时,
false被严格量化为 $0$,true则被量化为 $1$ [4780]。
Q20 【答案】错
- 解析:将一个整型变量赋值给浮点类型变量时,可能会带来表达精度的丢失。对于非常大或非常小的整型数值,由于浮点数内部尾数精度的物理存储位数限制,赋值后在低位可能会导致精度损失,从而改变数值的值。此外,赋值后数据类型发生了变化(例如
int变为float) [4781]。
Q21 【答案】错
- 解析:在 C++ 语言中,输出计算表达式的值不需要强制将其存储到特定变量中。我们直接使用输出流
std::cout << 表达式;或格式化printf即可无障碍地向终端输出计算结果 [5377]。
Q22 【答案】错
- 解析:Dev-C++ 是专门为 C/C++ 语言开发设计的集成开发环境(IDE),为程序开发者提供编辑、编译和代码调试支持。它是一套应用软件,运行于底层的计算机操作系统之上,本身不具备操作系统的内核硬件资源管理能力 [9783]。
Q23 【答案】对
- 解析:
for循环与while循环在基本控制流逻辑上是等价的。for(初始化; 条件; 步进)结构随时可以无缝改写为将“初始化”置于循环外,将“步进”置于循环体末尾,条件仍作为控制主体的while(条件)结构 [11072]。
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com