对应大纲: 2.1.2
的全部缺口——switch/do-while、指针与引用、结构体与联合体、字符串处理、函数与传参、作用域、STL、文件读写、运算符优先级、流程图
为什么单开一份: L01–L07
和 S1–S6
教的是算法,默认你语法都会。但初赛的单选题和阅读程序题大量考语法细节——本章补的就是这一层。
switch
与 do-while(Python 转过来的人必看)switchswitch (x) {
case 1: cout << "一"; break;
case 2: cout << "二"; break;
default: cout << "其他";
}⚠️ 三条铁律:
break 会「贯穿」——从匹配的
case 开始一直往下执行,直到遇到 break
或结尾。switch
的表达式必须是整型或字符型,不能是 double、不能是
string。写 switch(3.5)
编译报错:switch quantity not an integer。case
后面必须是常量,不能写区间(case 1..5
不合法),也不能写变量。📝 case
不是「分几个格子」,是「从哪儿开始往下跑」。
⚠️
成绩等级那种区间判断(
优秀、
良好…)用 switch 写不了,除非先
score / 10 转成整数档位。
do-whiledo {
// 循环体
} while (条件); // ← 这个分号必须有!和 while 的唯一区别:do-while
至少执行一次(先做再判断)。
⚠️ do {...} while (条件); 是整个 C++
里唯一一个「右括号后面要加分号」的地方——所以它才被反复考。
| 写法 | 后面要分号吗 |
|---|---|
if (...) {...} |
✗ 不要 |
for (...) {...} |
✗ 不要 |
while (...) {...} |
✗ 不要 |
do {...} while (...) |
✓ 必须要 |
⚠️ 反过来:for (...);
加了分号就变成空循环体,循环白跑一遍。这是初赛阅读程序题的常客——看到
for 或 if
后面紧跟分号,立刻警觉。
() [] -> . 最高
! ~ ++ -- (强制类型转换) 一元-
* / %
+ -
<< >>
< <= > >=
== !=
&
^
|
&&
||
?: 三目
= += -= ... 赋值(最低,右结合)
⚠️ 位运算的优先级比比较运算还低! 所以
if (x & 1 == 0) 实际是 x & (1 == 0) =
x & 0 = 0。必须写
if ((x & 1) == 0)。
⚠️ << 的优先级低于
+:cout << a + b 没问题,但
cout << a & b 会出事。
= 与 ==(每年都考)if (num = i * i) { ... } // 这是赋值!结果非零就永远为真
if (num == i * i) { ... } // 这才是比较⚠️ if (a = b)
能编译、能运行、大多数时候恒为真。 这是 C++ 最经典的坑(CSP
2024 第 19 题就考了这个空)。
| 表达式 | 结果 |
|---|---|
7 / 2 |
3(整除,直接砍掉小数) |
7.0 / 2 或 7 / 2.0 |
3.5 |
-7 / 2 |
-3(向零取整,不是向下取整) |
-7 % 2 |
-1(余数的符号跟被除数) |
x % 0 |
运行时崩溃(不是 0!) |
⚠️ n % 0 和 n / 0
都是致命错误,程序直接崩(CSP 2019 第 16 题实测退出码
INTEGER_DIVIDE_BY_ZERO)。
int a = 5, b = a++; // b = 5, a = 6 (后加:先交出旧值,再加)
int c = 5, d = ++c; // d = 6, c = 6 (前加:先加,再交出新值)📝 a 和 c 最后都是
6——变量自己一定加到 6,差别只在「交出去的那个值」。++
在前就先加,在后就后加。
⚠️ 不要去碰 a = a++ + ++a
这种,那是未定义行为,初赛不考。
int x = 10;
int *p = &x; // p 存的是 x 的地址
cout << *p; // 10 —— 解引用,取出 p 指向的值
*p = 20; // x 变成 20| 写法 | 改的是谁 |
|---|---|
p = q |
指针本身——让 p 改指向 q 所指的地方 |
*p = *q |
内容——把 q 指向的值抄给 p 指向的变量 |
⚠️ CSP 2022 第 3
题就考这一字之差:p = q 之后 x 和
y 的值一个都没变。
void solve(int &a, int b) { // a 是引用,b 是副本
a = 100; // 外面的实参真的变成 100
b = 200; // 白改
}📝 看到函数参数,第一件事:把带 &
的圈出来。 不带 &
的,函数里怎么改都跟外面无关。
⚠️ CSP 2025 第 10
题:void solve(int &a, int b)
里写了「不用临时变量交换两数」的经典三行,但只有一个参数是引用——交换废了一半,结果
。
a 等价于
&a[0]a[i] 等价于 *(a + i)sizeof 在函数里量不出数组长度struct Point { int x, y; }; // 每个成员各占各的
union Data { int n; float f; }; // 所有成员共用同一块内存struct |
union |
|
|---|---|---|
| 内存 | 各成员分别占用 | 全部共用一块 |
sizeof |
各成员之和(含对齐) | 最大成员的大小 |
| 有效成员 | 全部 | 只有最后写入的那个 |
⚠️ 访问成员:对象用 .,指针用
->。
Point p; p.x = 1; // 对象
Point *q; q->x = 1; // 指针,等价于 (*q).xCSP 2023 第 3 题就考这个:data 是
union Data 类型的对象,所以写
data.value = 3.14;(不是
->,也不是把变量名和成员名写反)。
char 数组(C 风格)char s[100];
scanf("%s", s); // 注意:s 前面不加 &
strlen(s); // 长度(不含 '\0')
strcpy(a, b); strcat(a, b); strcmp(a, b); // 需要 <cstring>⚠️ C 风格字符串以 '\0' 结尾,所以
char s[100] 最多存 99 个字符。
string 类(C++ 风格)#include <string>
string s;
cin >> s; // 读一个单词
getline(cin, s); // 读一整行
s.length() s.size() // 两个是同一个函数的两个名字,永远相等
s + "abc" s += 'a' // 可以直接拼接,也可以拼单个 char
s.substr(pos, len) s.find("x")⚠️ CSP 2025 第 9 题逐条考了 string
的四个说法,正确的只有「可以用 + 连接 string
和
char」。其余三个(长度不可变、length
和 size 可能不同、必须以 '\0' 结尾)都是把
char 数组的知识生搬过来的错误。
📝 一句话:string 自己管长度,不靠
'\0',而且能变长。
<cctype>)isdigit isalpha isupper
islower toupper tolower
| 概念 | 要点 |
|---|---|
| 形参 / 实参 | 定义时写的是形参,调用时传的是实参 |
| 传值 | 传副本,函数内修改不影响外面 |
传引用 & |
传本体,函数内修改会影响外面 |
| 返回值 | 一个函数只能返回一个值(要多个就用引用参数或结构体) |
| 局部变量 | 只在定义它的 {} 内有效,函数结束就消失 |
| 全局变量 | 全程序有效,自动初始化为 0 |
⚠️ 函数必须「先声明再使用」。 如果把函数定义放在
main 后面又没在前面加声明,编译直接报错
'xxx' was not declared in this scope(CSP 2021 第 16
题实测确认)。
📝 全局数组自动清零,局部数组不会。
int a[100]; 写在 main
里面,里面装的是垃圾值;写在 main 外面就全是
0。这也是竞赛里习惯把大数组开在全局的原因之一。
两个必备零件:① 递归出口(边界条件)② 每次调用规模都要变小。
⚠️ 少一个就是死循环 / 栈溢出。
📝 初赛的递归题一律列表格从小往大填,别在脑子里展开调用树。
| 名字 | 用途 |
|---|---|
min max swap |
基础 |
sort(a, a+n) |
排序,,不稳定 |
stable_sort |
稳定排序 |
lower_bound / upper_bound |
二分查找(要求已排序) |
vector |
变长数组 |
stack / queue |
栈 / 队列 |
详见 S4_vector与stack.md。
复赛必须用文件输入输出(第一轮不考实操,但会考概念):
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);详见 freopen函数用法教程.md。
📝 概念题要点:文本文件 vs
二进制文件;文件重定向的作用(不改 cin/cout
的写法就能读写文件)。
<cmath>)| 函数 | 作用 | ⚠️ |
|---|---|---|
abs / fabs |
整数 / 浮点绝对值 | |
floor / ceil |
下取整 / 上取整 | 返回值是 double |
round |
四舍五入 | |
sqrt |
平方根 | 负数返回 nan,不报错 |
pow(a, b) |
幂 | 返回 double,有精度问题 |
log / exp |
自然对数 / 指数 | |
sin cos tan |
三角函数 | 参数是弧度不是角度 |
⚠️ pow(result, 2) 返回的是
double,cout
打印时可能和整数不一样。CSP 2024 第 18
题就利用了「问的是函数返回值还是程序输出」的差别——输出是
pow(f,2),返回值是
f,差一个平方。
do {...} while (x);
后面要不要分号?for (...) {...} 呢?switch 的表达式可以是 double 吗?漏了
break 会怎样?if (x & 1 == 0) 有什么问题?int a=5, b=a++; 之后 a 和 b
各是多少?p = q 和 *p = *q 有什么区别?struct 和 union 的 sizeof
分别怎么算?string 的 length() 和 size()
会不同吗?string 要不要以 '\0' 结尾?do-while 要分号;for
不要(加了就是空循环体)break
会一直往下贯穿执行==,实际算的是
x & (1==0) = x & 0 = 0;要写
((x & 1) == 0)a = 6,b = 5struct 是各成员之和(含对齐);union
是最大成员的大小string
自己管长度)