给 B 班同学的话:
GESP 三级是编程学习的第一个真正的分水岭。一二级考的大多是语法基础(顺序、分支、循环),而三级开始,计算机底层原理(原码补码、进制、位运算)和核心数据结构与算法(数组、字符串、枚举、模拟)全面登场!
很多同学看到“补码”、“位运算”就觉得难,其实这完全是纸老虎。本手册专为 B 班同学编写,特点是:零黑话、全图解、步步推演、自带避坑指南。你不需要翻阅其他讲义,这一本手册就把三级考纲的所有知识点、易错题和编程考法全部打包吃透!
三级及格线是 60 分。只要把本手册的前半部分客观题规律吃透(稳拿 35~40 分),再把第一道编程题做对(稳拿 25 分),你就已经稳过 60 分了!
| 项目 | 内容 |
|---|---|
| 考试时长 | 120 分钟(2 小时) |
| 试卷满分 | 100 分(60 分及格过关并获得证书) |
| 题型分布 | 单选题 15 道(每题 2 分,共 30
分) 判断题 10 道(每题 2 分,共 20 分) 编程题 2 道(每题 25 分,共 50 分) |
| 开发环境 | Dev-C++ 5.11,标准为 C++11 |
| 模块 | 考纲知识点 | 对应手册章节 | 考题形式 | 难度星级 |
|---|---|---|---|---|
| M1 | 数据编码:原码、反码、补码 | 第一章 | 单选、判断 | ★★★☆☆ |
| M2 | 进位制与进制转换(二、八、十、十六) | 第二章 | 单选、判断、编程填空 | ★★☆☆☆ |
| M3 | 位运算:&、|、~、^、<<、>> |
第三章 | 单选、判断、编程 | ★★★☆☆ |
| M4 | 算法的概念与描述(自然语言、流程图、伪代码) | 第四章 | 单选、判断 | ★☆☆☆☆ |
| M5 | C++ 一维数组基本应用(定义、初始化、遍历、极值、统计) | 第五章 | 编程题第 1 题核心 | ★★☆☆☆ |
| M6 | 字符串 std::string 及常用函数 |
第六章 | 编程题第 2 题核心 | ★★★☆☆ |
| M7 | 核心算法一:枚举法(穷举) | 第七章 | 编程题 | ★★☆☆☆ |
| M8 | 核心算法二:模拟法 | 第八章 | 编程题 | ★★☆☆☆ |
| 附录 | B班必看:考场 5 大致命 Bug 抓虫实操 | 第九章 | 考场保命 | ★★★★★ |
| 真题 | GESP 三级全真题型实战演练(客观+编程) | 第十章 | 综合自测 | ★★★☆☆ |
大纲要求: 了解二进制数据编码:原码、反码、补码。
计算机内部所有的数都是以二进制形式存储的,而且计算机的 CPU 内部只有加法器,没有减法器!为了用加法来算减法(比如 当成 算),计算机科学家发明了原码、反码、补码。
现代计算机中,所有整数一律用【补码】存储和运算!
在一个有固定位数的二进制数中(通常以 8 位 byte 为例):
0
表示正数,1 表示负数。 符号位(0正1负)
↓
0 0 0 0 0 1 0 1 --> 这是 +5
1 0 0 0 0 1 0 1 --> 这是 -5 的原码
📝 金科玉律:正数的原码、反码、补码完全一模一样!根本不用算!
例如 (用 8 位二进制表示):
0000 01010000 01010000 0101负数的原码、反码、补码各不相同,换算口诀如下:
符号位填 1,后面写绝对值的二进制
负数数值 ──────────────────────────────────────────> 原码
│
符号位不变(仍为1),其余位按位取反 │ (0变1, 1变0)
↓
反码
│
│ 加 1
↓
补码
0000 0101,负数符号位填 1
原码:1000 01011 保持不动,后面 7
位全部取反
反码:1111 10101111 1011方法完全一样:取反再加 1(或者减 1 再取反)。
1111 1011;1000 0100;1000 0101,数值位是 5,所以原来代表
!很多同学问:8 个二进制位能表示 个状态,正数能到 ,负数为什么能到 ?
0000 0000 表示
;1000 0000 本来代表
,但数学上
,留着两个
0 纯属浪费;1000 0000 专门用来表示
!char)范围:(即
)。short)范围:(即
)。int)范围:(约
)。1111 1111 对应的十进制整数是多少?1000 0000,加 1
得:1000 0001,绝对值是 1,故为
。1111 0111
0000 1001;1000 1001;1111 0110;1111 0111。大纲要求: 掌握数据的进制转换:二进制、八进制、十进制、十六进制。
日常生活中我们习惯逢十进一(十进制),计算机硬件底层是高低电平(二进制),为了书写紧凑,编程中常借用八进制和十六进制。
| 进位制 | 英文与前缀标识 | 允许使用的数字符号 | 计数规则 |
|---|---|---|---|
| 二进制 | Binary(代码前缀 0b,后缀 B) |
0, 1 |
逢二进一 |
| 八进制 | Octal(代码前缀 0,后缀 O/Q) |
0, 1, 2, 3, 4, 5, 6, 7 |
逢八进一 |
| 十进制 | Decimal(无前缀,后缀 D) | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
逢十进一 |
| 十六进制 | Hexadecimal(代码前缀 0x,后缀 H) |
0~9 以及
A(10), B(11), C(12), D(13), E(14), F(15) |
逢十六进一 |
📝 口诀:从右往左数,第 位的数值 ( 从 0 开始算),全部加起来!
📝 口诀:一直除以基数(2、8、16),记下余数;直到商为 0;把所有余数从下往上(倒序)抄下来!
2 | 25 ...... 余数 1 (最后一位) ↑
+----+ │
2 | 12 ...... 余数 0 │
+----+ │ 倒
2 | 6 ...... 余数 0 │ 序
+----+ │ 抄
2 | 3 ...... 余数 1 │
+----+ │
2 | 1 ...... 余数 1 (第一位) │
+----+
0
结果:25 = (11001)₂
因为 ,,它们之间互转根本不需要先转十进制,直接分组即可!
【二进制 <---> 八进制】: 3 位一组(4-2-1 原则)
二进制: 0 0 1 1 0 1 0 1 0
八进制: 1 5 2 ==> (152)₈
【二进制 <---> 十六进制】:4 位一组(8-4-2-1 原则)
二进制: 0 1 1 0 1 1 0 1
十六进制: 6 D ==> (6D)₁₆ (注意 13 对应 D)
⚠️ 注意:分组时必须从小数点或最右边(个位)开始向左分,左边不够位数的补 0!
GESP 编程题经常考进制输出,C++ 标准库带有一套极其方便的格式控制符:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n = 43;
// 输出十进制、八进制、十六进制
cout << dec << n << endl; // 输出 43 (dec: decimal)
cout << oct << n << endl; // 输出 53 (oct: octal)
cout << hex << n << endl; // 输出 2b (hex: hexadecimal)
// 代码中直接书写不同进制字面量
int a = 0b1011; // 二进制 11
int b = 052; // 八进制 42 (以 0 开头)
int c = 0x2A; // 十六进制 42 (以 0x 开头)
cout << a << " " << b << " " << c << endl; // 默认均按十进制输出: 11 42 42
return 0;
}大纲要求: 掌握位运算:与(
&)、或(|)、非(~)、异或(^)、左移(<<)、右移(>>)的基本使用方法及原理。
位运算就是直接对整数在内存中的二进制位进行操作。速度极快,是计算机最高效的运算。
我们用一位二进制(只有 0 和 1)来建立口诀:
| 运算符 | 名称 | 规则口诀 | 运算法则 | 示例 () |
|---|---|---|---|---|
& |
按位与 | 全 1 才是 1,有 0 则为 0 | ||
| |
按位或 | 有 1 就是 1,全 0 才是 0 | ||
^ |
按位异或 | 相同为 0,不同为 1(求异) | ||
~ |
按位非(取反) | 黑白颠倒,0变1,1变0 | 包含符号位全部翻转 | |
<< |
左移 | 所有位向左推,低位补 0 | 每左移 1 位,相当于 | |
>> |
右移 | 所有位向右推,低位丢弃 | 每右移 1 位,相当于 (向下整除) |
if ((n & 1) == 1)
奇数(二进制最后一位是 1)。if ((n & 1) == 0)
偶数(二进制最后一位是 0)。n % 2 == 1 执行更快,而且对负数完全有效!n << 1 就是
;n << 3
就是
。n >> 1 就是
;n >> 2
就是
。n & (n - 1):正好把二进制中最右边的那个 1
变成 0!常用来统计一个数二进制中有几个 1。很多同学写下这行代码,怎么调都 WA(答案错误):
if (n & 1 == 0) // ❌ 严重错误!为什么错? 因为在 C++ 中,关系运算符 ==
的优先级远高于按位与 &!
上面的代码被系统自动理解成了:
if (n & (1 == 0)) --> 变成了 if (n & 0) --> 永远是假(false)!📝 保命法则:只要写位运算,必须给位运算加括号!无条件写成:
if ((n & 1) == 0)
大纲要求: 了解算法的概念与描述,熟练运用自然语言、流程图、伪代码方式来描述算法。
算法就是解决问题的一系列明确指令与计算步骤。不是所有过程都能叫算法,算法必须同时具备 5 大特性(选择题必考):
| 描述方式 | 特点 | 优缺点 |
|---|---|---|
| 自然语言 | 用中文/英文文字逐步叙述(如“第一步...第二步...”) | 通俗易懂,但容易产生歧义、文字冗长 |
| 流程图 | 用统一规范的几何图形框和箭头表示 | 直观清晰、逻辑顺序一目了然,但绘制繁琐 |
| 伪代码 | 介于自然语言与编程语言之间(类似不写头文件的精简代码) | 结构分明、书写自由、方便直接转换成 C++ 代码 |
╭──────────╮
│ 开始/结束 │ <-- 圆角矩形 / 椭圆形:表示算法的【起止】
╰─────┬────╯
│
▼
/ 输入/输出 / <-- 平行四边形:表示数据的【输入或输出】
/─────────────/
│
▼
┌──────────┐
│ 处理框 │ <-- 矩形:表示计算、赋值、数据处理
└─────┬────╯
│
▼
/ \
/ 条件 \ <-- 菱形:表示【判断/分支】(根据真假分两路走)
\ 判定 /
\ /
GESP 单选题常给出一段伪代码,问输出是什么。看懂伪代码的绝招是:在草稿纸上画表格,一步一步模拟变量的变化(跟踪变量法)。
伪代码示例:
输入 N
ans <- 0
i <- 1
WHILE i <= N DO
IF i MOD 2 = 0 THEN
ans <- ans + i
END IF
i <- i + 1
END WHILE
输出 ans
分析:MOD 是取余
%,<- 是赋值 =。 这就是在统计
之间所有偶数的和!若输入
,偶数是
2, 4, 6,输出就是
。
大纲要求: C++ 一维数组基本应用(不包括变长数组),包括定义、初始化、遍历、求和、最大最小值、统计等。
变量就像一个单个储物格,而数组就是一整排编号相连的储物柜。
// 1. 数组定义:类型 数组名[固定长度];
int a[10]; // 定义了一个长度为 10 的整型数组,下标是 0 到 9!
// 2. 初始化全为 0(极度推荐)
int b[10] = {0}; // 10 个格子全部初始化为 0
// 3. 部分显式初始化
int c[5] = {1, 2}; // 前两个是 1, 2,后面三个自动补 0:1, 2, 0, 0, 0⚠️ B 班最致命警示:下标永远从 0 开始! 定义
int a[10];,合法的格子只有:a[0], a[1], a[2], ..., a[9]。 根本不存在a[10]! 访问a[10]叫数组下标越界,考试会导致死机或被判 0 分!
main 函数外面的叫【全局数组】:
main 函数里面的叫【局部数组】:
main 函数外面(全局)!int n;
cin >> n;
int a[1005];
for (int i = 0; i < n; i++) {
cin >> a[i]; // 从 0 循环到 n-1 读入
}
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
cout << endl;long long sum = 0; // 求和变量记得先清 0!
for (int i = 0; i < n; i++) {
sum += a[i];
}
double avg = (double)sum / n; // ⚠️ 注意强转 double,保留小数int max_val = a[0]; // 先让第 0 个人当擂主!
int max_idx = 0; // 记录最大值所在的下标
for (int i = 1; i < n; i++) {
if (a[i] > max_val) {
max_val = a[i]; // 发现更厉害的,新擂主上位
max_idx = i;
}
}
cout << "最大值是 " << max_val << ",位置是 " << max_idx << endl;⚠️ 坑点:找最大值千万不要盲目把初值设为 0!如果数组里全是负数(比如
-5, -10, -3),初值写 0 输出结果就会错成 0!最佳初值永远是a[0]。
int count_pass = 0;
for (int i = 0; i < n; i++) {
if (a[i] >= 60) {
count_pass++;
}
}// 将 a 数组就地翻转
int l = 0, r = n - 1;
while (l < r) {
swap(a[l], a[r]); // 交换首尾元素
l++;
r--;
}大纲要求: 掌握字符串及其函数的使用,包括但不限于大小写转换、字符串搜索、分割、替换。
在 C++ 中,推荐使用强大的 string 类(需要包含头文件
<string> 或
<bits/stdc++.h>)。
cin >> s;(遇到空格或回车就停止)。getline(cin, s);。s.size() 或
s.length()。s[0] 是第 1
个字符,s[s.size() - 1] 是最后一个字符。字符串: "H e l l o"
下标: 0 1 2 3 4 (长度 s.size() 是 5)
⚠️ 避坑秘笈:
cin >>与getline混用的换行残留坑 如果先用cin >> n读了一个数字,紧接着用getline(cin, s)读一整行,你会发现s读到的是个空串!因为cin >> n把末尾的回车符留在了缓冲区里。 解法:在getline之前加一句cin.ignore();吃掉回车!cin >> n; cin.ignore(); // 关键!清空回车 getline(cin, s);
#include <bits/stdc++.h>
using namespace std;
int main() {
string s = "Hello C++ World";
// 1. 截取子串: s.substr(起始位置, 截取长度)
string sub = s.substr(6, 3); // 从下标 6 开始切 3 个字符
cout << sub << endl; // 输出 "C++"
// 2. 查找子串: s.find(目标串)
// 找到了返回第一次出现的下标;找不到返回 string::npos (不要写 -1)
int pos = s.find("C++");
if (pos != string::npos) {
cout << "找到了,下标在:" << pos << endl; // 6
}
// 3. 替换子串: s.replace(起始位置, 替换长度, 新串)
s.replace(6, 3, "Python");
cout << s << endl; // "Hello Python World"
// 4. 字符串拼接
string a = "Good", b = "Job";
string c = a + " " + b; // "Good Job"
// 5. 字符串反转 (使用 <algorithm> 里的 reverse)
string rev = "12345";
reverse(rev.begin(), rev.end());
cout << rev << endl; // "54321"
return 0;
}| 需求 | 标准写法 | 原理说明 |
|---|---|---|
| 判断是否是大写字母 | if (c >= 'A' && c <= 'Z') 或
isupper(c) |
利用 ASCII 码连续性 |
| 判断是否是数字字符 | if (c >= '0' && c <= '9') 或
isdigit(c) |
字符 '0' 是 48 |
| 大写转小写 | c = tolower(c); 或 c = c + 32; |
小写比大写大 32 |
| 小写转大写 | c = toupper(c); 或 c = c - 32; |
大写比小写小 32 |
| 数字字符转对应整数 | int num = c - '0'; |
比如 '7' - '0' = 7 |
| 整数转数字字符 | char c = num + '0'; |
比如 7 + '0' = '7' |
大纲要求: 理解枚举算法的原理及特点,可以解决实际问题。
枚举法(又称“笨办法”或暴力求解):把所有可能的答案一个一个拿来检验,符合题目条件的就留下,不符合的就扔掉。
📝 B 班枚举三步法:
- 枚举谁?(确定循环变量,例如从 1 到 );
- 范围多大?(初始值是谁?结束值是谁?例如水仙花数范围是 );
- 怎么验证?(写一个
if语句,符合条件的统计或打印)。
问题:求所有三位数中,各位数字立方和等于该数本身的数字(如 )。
#include <bits/stdc++.h>
using namespace std;
int main() {
// 1. 明确范围:所有三位数就是 100 到 999
for (int i = 100; i <= 999; i++) {
// 2. 分解各位数字
int g = i % 10; // 个位
int s = (i / 10) % 10; // 十位
int b = i / 100; // 百位
// 3. 条件判断
if (b * b * b + s * s * s + g * g * g == i) {
cout << i << " ";
}
}
cout << endl;
return 0;
}输出:153 370 371 407。
百钱买百鸡:公鸡 5 元一只,母鸡 3 元一只,小鸡 1 元三只。用 100 元买 100 只鸡。
for(x)、for(y)、for(z),执行
次。大纲要求: 理解模拟算法的原理及特点,可以解决实际问题。
模拟法就是题目怎么说,你就让代码怎么一步一步走。 题目是考官出的剧本,代码是演员,按照剧本分毫不差地演一遍。
📝 模拟法核心三步:
- 定义状态:用哪些变量表示当前的情况?
- 推进一步:状态如何发生变化?(如时间加 1、小人走一步、数字发生改变);
- 结束条件:什么时候停止?
题目描述:给定一个正整数 。如果是奇数,乘 3 加 1;如果是偶数,除以 2。重复该过程,直到 变成 1。输出一共变换了多少次。
#include <bits/stdc++.h>
using namespace std;
int main() {
long long n; // 过程中可能超出 int 范围,稳妥起见开 long long
cin >> n;
int step = 0;
// 终止条件:n == 1
while (n != 1) {
if (n % 2 == 1) {
n = n * 3 + 1; // 奇数:乘3加1
} else {
n = n / 2; // 偶数:除以2
}
step++; // 步数累加
}
cout << step << endl;
return 0;
}很多同学自学了很久,知识点全都会,一考就只有 40 分。以下是 B 班最容易丢分的 5 大坑,请当成考前疫苗仔细研读!
// 错误写法:
if (x & 1 == 0) // 编译器先算 1 == 0 (得 0),变成 if(x & 0),永远不成立!
// ✅ 正确保命写法:必须带外层括号
if ((x & 1) == 0)// 错误写法:
int max_val = 0;
for (int i = 0; i < n; i++) {
if (a[i] > max_val) max_val = a[i];
}
// 如果输入数组全是负数:-10, -5, -8
// 输出是 0!实际上答案应该是 -5!
// ✅ 正确保命写法:直接用第 0 个元素当擂主
int max_val = a[0];
for (int i = 1; i < n; i++) {
if (a[i] > max_val) max_val = a[i];
}int a[100];
int n;
cin >> n; // 假设 n = 100
for (int i = 1; i <= n; i++) cin >> a[i]; // 当 i = 100 时,访问了 a[100]!越界!
// ✅ 正确保命写法:
// 习惯 1:大小多开 10 个空间!比如范围是 100,数组就开 110:int a[110];
// 习惯 2:严格使用 0 到 n-1 下标:for(int i = 0; i < n; i++) cin >> a[i];int a = 7, b = 2;
double ans = a / b; // ❌ 结果是 3.0,不是 3.5!因为 a/b 先按 int 算成了 3
// ✅ 正确保命写法:至少一边强制转 double
double ans = (double)a / b; // 3.5
// 或者:
double ans = a * 1.0 / b; // 3.5int n;
string s;
cin >> n;
getline(cin, s); // ❌ 此时 s 读到的是 n 后面的回车符,是空串!
// ✅ 正确保命写法:
cin >> n;
cin.ignore(); // 把回车符吃掉
getline(cin, s); // 顺利读入后面的整行文本【题 1·单选题】
在计算机内部,有符号整数通常采用下列哪种编码形式进行存储和计算? A.
原码
B. 反码
C. 补码
D. ASCII 码
【解析】 答案为 C。现代计算机体系结构中,为了统一加减法并消除 和 的歧义,所有整数一律采用补码。
【题 2·单选题】 十六进制数 0x2F
转换成十进制数是( )。 A. 45
B. 47
C. 57
D. 31
【解析】 答案为 B。按权展开:。
【题 3·单选题】 表达式
(7 & 3) | (8 >> 2) 的计算结果是( )。 A. 2
B. 3
C. 5
D. 7
【解析】 答案为 B。
- ,,;
- ,右移 2 位得到 ;
- 。
【题 4·单选题】 8 位二进制补码
1000 0000 表示的十进制整数是( )。 A. 0
B. -127
C. -128
D. 128
【解析】 答案为 C。这是考纲明文规定的边界特值,8 位补码
1000 0000规定代表 。
【题 5·判断题】 在 C++ 语言中,定义数组
int a[5]; 后,访问 a[5]
在语法上一定能通过编译,但运行时属于未定义行为(越界)。( ) A.
正确
B. 错误
【解析】 答案为 A。C++ 编译器通常不检查静态数组下标越界,能正常编译,但运行期非法访问会导致程序异常,考场严禁越界。
【题 6·单选题】 阅读以下伪代码,若输入为
5,输出结果是( )。
输入 N
s <- 1
i <- 1
WHILE i <= N DO
s <- s * i
i <- i + 1
END WHILE
输出 s
A. 15
B. 25
C. 120
D. 720
【解析】 答案为 C。变量跟踪:。实际上计算的是 5 的阶乘 。
题目描述: 某学校组织期中测试,有 名学生()。给出每名学生的成绩( 的整数)。 请你编写程序,计算并输出:
- 全班最高分;
- 全班平均分(保留两位小数);
- 高于(大于)平均分的人数。
输入样例:
5 80 90 70 60 100输出样例:
100 80.00 2
1005 的全局数组 a。sum;max_score。double avg = (double)sum / n;。avg。#include <bits/stdc++.h>
using namespace std;
int a[1005];
int main() {
int n;
if (!(cin >> n)) return 0;
long long sum = 0;
int max_score = -1; // 成绩非负,初值设 -1 极其安全
for (int i = 0; i < n; i++) {
cin >> a[i];
sum += a[i];
if (a[i] > max_score) {
max_score = a[i];
}
}
double avg = (double)sum / n;
int above_cnt = 0;
for (int i = 0; i < n; i++) {
if (a[i] > avg) {
above_cnt++;
}
}
// 格式化输出
cout << max_score << endl;
cout << fixed << setprecision(2) << avg << endl;
cout << above_cnt << endl;
return 0;
}题目描述: 输入一行字符串(可能包含大小写字母、数字、空格和特殊字符,长度不超过 200)。 请进行如下处理并按格式输出:
- 将所有的大写字母转换成小写字母;
- 统计其中数字字符(
0~9)的总个数;- 输出处理后的新字符串,并在下一行输出数字字符的总数。
输入样例:
CSP 2026 Junior & GESP Grade 3!输出样例:
csp 2026 junior & gesp grade 3! 5
cin >> s;,必须使用
getline(cin, s);!s.size() - 1;isdigit(s[i]) 或
s[i] >= '0' && s[i] <= '9'
判断是否是数字,计数器加 1;tolower(s[i]) 将字符转为小写。#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
getline(cin, s); // 整行读入,包含空格
int digit_cnt = 0;
for (int i = 0; i < (int)s.size(); i++) {
// 统计数字个数
if (s[i] >= '0' && s[i] <= '9') {
digit_cnt++;
}
// 转换小写
s[i] = tolower(s[i]);
}
cout << s << endl;
cout << digit_cnt << endl;
return 0;
}每位 B 班同学在考前一晚,请对着以下 7 个问题默问自己,能够脱口而出就算达标:
祝所有 B 班同学稳定发挥,一次高分通过 GESP 三级认证!