C++竞赛语法基础
首先声明!!!
- 1、此知识点为课堂总结内容;
- 2、如有使用或转载请注明出处;
- 3、如有不足,欢迎批评指正;
* C++导言.软件
1. 导言须知
-
课程方向:
-
知识点主要面向小学**5年级+**的少儿编程 C++ 课程,适用于信奥赛选拔;
-
特别注意①:C++ 课程 只有启蒙这一套是 小学阶段适合,后续全部中学;
-
特别注意②:虽然是 C++ 编程课程,但和 C++ 几乎没有关系,如何理解?
- 很多学习者在学习时,找那种职业成人的C++课程,咨询学了是否可以打比赛?
- 你学习的是信息学奥林匹克竞赛之启蒙阶段,只不过用了官方推荐的 C++ 环境罢了;
- 如果官方推荐了别的编程环境,学习的内容区别不大,用不到 C++ 自身的特性;
- 比如 C++ 可以做嵌入式开发、客户端服务端开发、音频视频开发、大型游戏开发等;
- 上面所说的东西,都不会学到,根本用不到 C++ 的各种能力。
- 而我们学习的是通过 C++ 编程环境,去解决计算机思维运算下的数理逻辑题罢了。
- 总结:我们的目的是 答题,不是做 开发。说白了就是 数学应用题考试。
-
-
知识点规划:
-
启蒙阶段(本套):
- 语法基础、分支、循环、数组、函数、字符串、结构体;
- 其中函数的递归详解或深入、数组中的排序算法、字符串的进制、编码、位运算不包含;
-
后续阶段(非本套):
- 过渡篇:进制转换、编码、位运算、暴力枚举、高精度等;
- 排序篇:冒泡、插入、选择、快速、归并、sort 排序等;
- 算法篇:递归、递推、模拟、分治、二分、贪心、倍增等;
- 搜索篇:深度优先DFS、广度优先BFS、回溯、剪枝等;
- 数据结构篇:链表、队列、栈、二叉树、并查集等;
- 图论篇:图的存储、最小生成树、最短路、二分图等;
- 动态规划篇:背包DP、线性DP、树形DP、区间DP、记忆化搜索等;
- 数论篇:筛质数、分解质因数、快速幂、组合数等;
-
详情参考:
- 上面只列出了大概知识点,详情参考:学习路线 - OI Wiki (oi-wiki.org)
- 一般培训机构,大概率只会做到 CSP-J/S 入门级的比赛,难度尚可;
- 更高级的比如 NOIP 或 同等 或 更高,NOIP 只能教一点,再多就能力不够了;
-
2. 软件使用
-
下载安装:
- 官网:DevC++
- 安装后推荐皮肤和设置,并根据自己的喜好调整:
-
第一个C++程序:
1
2
3
4
5
6
7
using namespace std;
int main()
{
cout << "Hello World!";
return 0;
} -
程序详解:
-
真正需要理解的就一行:cout << “Hello World!”;
- cout 表示 输出,直白点:运行程序后在窗口显示后面双引号里面的内容;
- << 表示 插入运算符,语法表示:在 cout 和 后面输出内容,需要用这个+空格隔开;
- ; 表示语句结束,一条输出语句写完后,需要通过分号表示结束;
-
其余的代码部分,全员基本格式,无须理解,做成模板自动即可;
- 虽说无须理解,但还是象征性的解释一下:
- include:头文件,导入外部库;iostream 表示支持输入输出;
- using…:命名空间,防止冲突;
- int main:主函数,程序会从这里执行;
- return 0:返回0,表示程序在这里结束;
- 虽说无须理解,但还是象征性的解释一下:
-
一、变量存储.注释
1. 变量声明
-
什么是变量?变量就是一个可以存储东西的存储罐,具体特性如下:
- 每次存储罐里只能存一次东西,也就是说再次存储时,上一次存储的东西会被替换掉;
- 声明变量就好比你拿出了一个存储罐,实际上是在内存里开辟了一个空间;
- 不管是现实中的存储罐还是内存开一个空间,多了防止混淆就需要贴个标签,命个名;
- 我们来通过一张图来理解一下,这个声明概念:
-
那么,如何通过编程来实现变量的声明呢?
1
2
3
4
5
6
7// 声明一个变量a,类型是整数
int a;
// 注意1:= 不是等于的意思,是赋值的意思
// 注意2:阅读代码从右边向左边阅读,意为:将数字123赋值给变量a
a = 123;
// 输出变量a
cout << a;
2. 命名规则
-
从 a=123 的例子中,a是变量名,但变量的名字有什么要求?需要注意哪些规则?能乱起吗?
-
变量名只能是:a-z、A-Z、0-9以及下划线组成;
-
变量名第一位不可以是数字;
-
变量名不可以是 C++ 关键字:比如 int main 之类的;
-
变量需要定义后才可以使用:int a; a = 123;
-
变量名区分大小写,A和a不同;
- abc(合法)、a123(合法)、_xyz(合法)、123a(不合法)
-
-
为了让变量名更加的有可读性,比如:你的名字:
- 第一种经典命名方式,驼峰式:yourName,或YourName,我比较喜欢前者;
- 第二种经典命名方式:蛇形式:your_name,用的也比较多;
1
2
3
4
5// 声明一个字符串
string yourName;
// 字符串类型,需要双引号包含
yourName = "你的名字";
cout << yourName;
二、四则运算.输入
1. 加减乘除
虽说叫做四则运算,但其实运算符往往不止加减乘除这四种:
| 运算 | 符号 | 格式 |
|---|---|---|
| 加 | + | 1 + 1 |
| 减 | - | 2 - 1 |
| 乘 | * | 3 * 4 |
| 除 | / | 6 / 2 |
| 取余 | % | 10 % 7 |
| 累加 | ++ | i++ |
| 累减 | – | i– |
-
在编程语法中乘法 x 用 * 代替,除法 ÷ 用 / 代替。
1
2
3
4
5
6// endl 表示换行 Ctrl + D复制一行
cout << 1 + 1 << endl;
cout << 3 - 2 << endl;
cout << 4 * 5 << endl;
cout << 9 / 7 << endl;
cout << 7 % 3 << endl;
2. cin 输入
如果想让用户在键盘输入内容,可以使用 cin 关键字;
1 | // 同时声明两个整型变量 |
三、学会使用OJ答题
1. OJ系统
所谓的OJ系统,即:用于竞赛编程中,海量刷题的工具系统;
-
这里推荐几个刷题的OJ平台:
- Codeforces:俄罗斯线上竞赛OJ
- Atcoder:日本线上竞赛OJ
- Codechef:印度尼西亚线上竞赛OJ
- 洛谷:常用刷题OJ
- 牛客网:常用周赛OJ
-
这里摘一段博宜答题须知:
- 程序题和平时纸上做的数学题不同,它包括了很多部分:题目、输入输出要求、输入输出样例、数据范围和时间限制和样例解释(说明)这几大部分,这几个部分都非常重要,每一部分都要看!!!
- 提交代码前必须要完成的三步!!!
1、在编译器里写完程序后要先编译通过(Devc++是弹出黑框框);
2、把题目是输入样例复制进去,用程序跑一遍,和题目给的输出样例对上了;
3、再检查一下程序,看有没有其他的一些情况没有考虑到的,检查无误后方可提交; - 不要有多余的输入输出!!!输出格式和题目要求要完全一致;
- 样例只是其中一个测试点,并非全部,后台会有很多其他数据测试你这个程序的。
- 比如:要求输入1和2,输出和3;
- 你不能 输入1和2,输出3
- 你应该 输入1和2,输出1+2
- 因为其它测试点可能是4和5,要求输出9
2. 使用洛谷
-
在首页直接输入题号:B2002,可直接进入题目页面;题号不区分大小写;
-
或者在右侧,有一个 题单 >> 【入门1】顺序结构 >> 题目列表 >> B2002 Hello,World!
-
开始读题;
-
在 Dev-C++编译器上 编写代码,并 编译 + 运行 结果;
-
将代码复制,回到答题页,选择 提交答案;
-
选择 C++ 标准 ,最近的就行,提交测评;
-
出现全部都是 绿色AC,表示正确,如果答案不对:则有可能会出现以下错误:WA(答案错误)、RE(越界问题)、TLE(时间超限)、MLE(内存超限)、CE(编译错误);
1
2
3
4
5
6
7
using namespace std;
int main() {
cout << "Hello,World!";
return 0;
}
-
四、数据类型.转换
1. 数据类型
| 类型名 | 类型声明 | 解释说明 |
|---|---|---|
| 整型 | int | -2147483648 到 2147483647 的范围的整数 |
| 长整形 | long long | 比上面大很多很多,这里装不下,具体搜索 |
| 字符型 | char | 赋值只能是一个字符,比如 ‘A’,必须用单引号,双表示字符串不是字符 |
| 浮点型 | float | 也叫实型或小数型,38位以内的小数,只保留6为有效数字 |
-
其实还有很多类型,暂时先理解这几个,后续用到的再单独讲解;
1
2
3
4
5
6
7
8
9
10// 字符型,切记是单引号
char ch = 'a';
// 长整形
long long b = 100000000000000000;
// 浮点型,只能六位
float c = 3.1415926;
cout << b << endl;
cout << ch << endl;
cout << c << endl;
return 0;
2. 类型转换
-
这里我们只探讨整数和小数之间的转换,其它的放到以后;
-
类型转换分为两种:隐式转换和强制转换;
1
2
3
4
5
6
7
8// 两边都是整数,结果也是整数:1
cout << 8 / 5 << endl;
// 两边有一边是浮点,结果是浮点:1.6
cout << 8.0 / 5 << endl;
// 强制转换浮点,float()是转换函数,将整数转换成浮点数,8叫做参数
cout << float(8) / 5 << endl;
// 强制转换整型
cout << int(3.14 * 5.25) << endl;
3. 保留小数点
-
首先要引入相关库:
-
其次使用 setprecision(n) 函数 来设置保留小数点的位数;
1
2
3// 输出保留的小数点
// fixed可以在缺少的位数补零,这样就精确保证2位
cout << fixed << setprecision(2) << 3.1415926;
习题一:1029.倒序输出一个四位整数

* 代码详解
1 | // 输入一个四位整数 |
五、输入输出.格式化
1. 输出
对于格式化输出,本节课将学习两个函数 scanf() 、 printf() 来取代之前的cin和cout方法;
- 假如,我们要输出一组运算等式:1 + 2 = 3,而1是变量a,2是变量b,3是a+b的运算结果;
1 | int a = 1, b = 2; |
-
printf() 函数极其方便的原因,它可以先按照自己的输出格式,先写出来,不需要头脑翻译;
-
然后把需要替换成变量的部分,用 %d 来表示即可,而后续对应的位置换成变量或表达式运算即可;
-
%d 这里表示占位的内容 是 整型,也有各种其它的占位符,这里罗列出常用的几个:
占位控制符 说明 %d 整数 %f 浮点数(float) %c 字符 %s 字符串 -
最终的语法结构如下:
1
printf(格式控制符, 占位替换列表)
2. 输入
-
从上面例子中,我们使用 scanf() 函数来控制输入:
1
2
3
4
5
6int a, b;
// scanf
scanf("%d %d", &a, &b);
// printf
printf("%d + %d = %d", a, b, a + b); -
先了解下输入参数的格式需求:
1
scanf(格式控制符, 地址集)
-
暂时没有办法解释这个地址是什么意思?举个并不恰当但好理解的说明:
- 快递员给张三寄快递,直接送到张三手上;这是 cin
- 快递员给张三家地址寄快递,不管是凤巢、门卫代收还是家人收件,最终会交给张三;这是 scanf()
- 所以,a表示张三,&a表示张三家的地址;而sacanf() 参数要求是地址,故在变量前加&;
- 而这个知识点叫做 引用,是比较靠后的知识点,暂时不用理解;
- 后续,自然也会有 变量本身就是引用,反而参数不需要 & 符号;
3. 格式化
-
在使用 printf() 时,我们需要输出各种特殊字符,比如百分号,换行,以及场宽精度问题等:
符号 说明和示例 \\ 输出一个斜杠,printf(“\\”); \n 换行,printf(“\n”); %% 百分号,printf(“%”); 数字 场宽,printf(“%3d%5d”); 小数 精度,printf(“%.2f”, 3.1415926); 1
2
3
4
5
6
7
8// 格式化
printf("%%\\\n");
// 场宽
printf("%3d%5d\n", a, b);
// 精度
printf("%.2f\n", 3.1415926);
// 场宽+精度
printf("%8.2f", 3.1415926);
习题二:P5705.数字反转

* 代码详解
1 | // 输入一个浮点数,只有一位小数 |
六、运算符表达式.布尔
1. 关系运算符
布尔类型的值,是专门用于各种表达式的判断,只存在两种值:
1 | // 布尔类型,只有两种值:true和false |
- 除了直接赋值为 true 或 false,也可以通过关系运算符来返回布尔值的数据:
| 名称 | 关系运算符 | 表达式返回值 |
|---|---|---|
| 大于 | > | 成立返回 true(6 > 5),否则为 false(6 > 7) |
| 小于 | < | 成立返回 true(6 < 8),否则为 false(6 < 5) |
| 等于 | == | 成立返回 true(6 == 6),否则为 false(6 == 7) |
| 大于等于 | >= | 成立返回 true(7 >= 6),否则为 false(7 >= 8) |
| 小于等于 | <= | 成立返回 true(6 <= 6),否则为 false(6 <= 5) |
| 不等于 | != | 成立返回 true(6 != 5),否则为 false(6 != 6) |
1 | // 返回 true(1) 和 false(0) |
2. 逻辑运算符
除了关系运算符之外,还有一种叫做逻辑运算符,具体如下:
| 名称 | 逻辑运算符 | 表达式返回值 |
|---|---|---|
| && | x && y | 表示and,x 和 y 同时为 true 时,返回 true,否则返回 false |
| || | x || y | 表示or, x 和 y 只要其中之一为 true,返回 true,否则返回 false |
| ! | !x | 表示not, x 为 true 时,结果为 false,否则为 true |
1 | # 逻辑运算符 |
习题三:B2040.判断是否为两位数

* 代码详解
1 | int a; |
* 补充:C++ 运算符优先级总表
来自 C++ 运算符优先级 - Oi-Wiki ,有修改。
| 运算符 | 描述 | 例子 | 可重载性 |
|---|---|---|---|
| 第一级别 | |||
| :: | 作用域解析符 | Class::age = 2; | 不可重载 |
| 第二级别 | |||
| ++ | 后自增运算符 | for (int i = 0; i < 10; i++) cout << i; | 可重载 |
| – | 后自减运算符 | for (int i = 10; i > 0; i–) cout << i; | 可重载 |
| type() type{} | 强制类型转换 | unsigned int a = unsigned(3.14); | 可重载 |
| () | 函数调用 | isdigit(‘1’) | 可重载 |
| [] | 数组数据获取 | array[4] = 2; | 可重载 |
| . | 对象型成员调用 | obj.age = 34; | 不可重载 |
| -> | 指针型成员调用 | ptr->age = 34; | 可重载 |
| 第三级别 | (从右向左结合) | ||
| ++ | 前自增运算符 | for (i = 0; i < 10; ++i) cout << i; | 可重载 |
| – | 前自减运算符 | for (i = 10; i > 0; --i) cout << i; | 可重载 |
| + | 正号 | int i = +1; | 可重载 |
| - | 负号 | int i = -1; | 可重载 |
| ! | 逻辑取反 | if (!done) … | 可重载 |
| ~ | 按位取反 | flags = ~flags; | 可重载 |
| (type) | C 风格强制类型转换 | int i = (int) floatNum; | 可重载 |
| * | 指针取值 | int data = *intPtr; | 可重载 |
| & | 值取指针 | int *intPtr = &data; | 可重载 |
| sizeof | 返回类型内存 | int size = sizeof floatNum; | 不可重载 |
| 第四级别 | |||
| .* | 类对象成员引用 | obj.*var = 24; | 不可重载 |
| ->* | 类指针成员引用 | ptr->*var = 24; | 可重载 |
| 第五级别 | |||
| * | 乘法 | int i = 2 * 4; | 可重载 |
| / | 除法 | float f = 10.0 / 3.0; | 可重载 |
| % | 取余数(模运算) | int rem = 4 % 3; | 可重载 |
| 第六级别 | |||
| + | 加法 | int i = 2 + 3; | 可重载 |
| - | 减法 | int i = 5 - 1; | 可重载 |
| 第七级别 | |||
| << | 位左移 | int flags = 33 << 1; | 可重载 |
| >> | 位右移 | int flags = 33 >> 1; | 可重载 |
| 第八级别 | |||
| < | 小于 | if (i < 42) … | 可重载 |
| <= | 小于等于 | if (i <= 42) … | 可重载 |
| > | 大于 | if (i > 42) … | 可重载 |
| >= | 大于等于 | if (i >= 42) … | 可重载 |
| 第九级别 | |||
| == | 等于 | if (i == 42) … | 可重载 |
| != | 不等于 | if (i != 42) … | 可重载 |
| 第十级别 | |||
| & | 位与运算 | flags = flags & 42; | 可重载 |
| ^ | 位异或运算 | flags = flags ^ 42; | 可重载 |
| | | 位或运算 | flags = flags | 42; | 可重载 |
| 第十一级别 | |||
| && | 逻辑与运算 | if (conditionA && conditionB) … | 可重载 |
| || | 逻辑或运算 | if (conditionA || conditionB) … | 可重载 |
| 第十二级别 | (从右向左结合) | ||
| ? : | 条件运算符 | int i = a > b ? a : b; | 不可重载 |
| = | 赋值 | int a = b; | 可重载 |
| += | 加赋值运算 | a += 3; | 可重载 |
| -= | 减赋值运算 | b -= 4; | 可重载 |
| *= | 乘赋值运算 | a *= 5; | 可重载 |
| /= | 除赋值运算 | a /= 2; | 可重载 |
| %= | 模赋值运算 | a %= 3; | 可重载 |
| <<= | 位左移赋值运算 | flags <<= 2; | 可重载 |
| >>= | 位右移赋值运算 | flags >>= 2; | 可重载 |
| &= | 位与赋值运算 | flags &= new_flags; | 可重载 |
| ^= | 位异或赋值运算 | flags ^= new_flags; | 可重载 |
| |= | 位或赋值运算 | flags |= new_flags; | 可重载 |
| 第十三级别 | |||
| , | 逗号分隔符 | for (i = 0, j = 0; i < 10; i++, j++) … | 可重载 |
七、分支语句.条件判断
1. if…单一条件
假设你一周七天中只有周一才能穿新衣服,那么就需要 if语句 中 单一条件判断:

-
单一条件判断的if语句格式如下:
1
2
3
4
5
6
7
8
9
10
11// 第一个花括号放在第一行末,或第二行开头均可,执行语句需要缩进一个Tab键
if (条件表达式) {
条件成立执行这里;
}
// 注意1:如果成立后的语句只有一句,可以去掉花括号,或放在第一行末
if (条件表达式) 条件成立执行这里;
// 或
if (条件表达式)
条件成立执行这里;1
2
3
4
5
6
7int flag;
cin >> flag;
// flag == 1 返回布尔值,成立的话执行缩进的第一行语句
// 如果有缩进的第二行,且没有括号包含,则无效
if (flag == 1)
cout << "周一穿新衣!";
2. if…else分支
单一if语句比较高冷,如果未满足条件,ta就不理你了;而else分支则可爱许多;

- else分支条件判断的if语句格式如下:
1 | if (条件表达式) { |
1 | // 单行语句 |
习题四:1632.需要几辆车

* 代码详解
1 | int n, a; |
习题五:1045.能否构成三角形

* 代码详解
1 | int a, b, c; |
习题六:1718. 闯关大冒险?

* 代码详解
1 |
|
八、多重判断.嵌套判断
1. else if…分支
很多时候的分支判断,可能不止一条或两条,此时就需要使用 else if 多重分支结构
1 | if (表达式成立) { |
1 | // 8岁之前:成长阶段 |
2. 嵌套判断
在某一个成立的条件下,是否还有不同的另外的条件判断呢,此时需要用到嵌套判断
1 | } else { |
习题七:P5715.三位数排序

* 代码详解
1 | int a,b,c; |
习题八:1667.最大和最小数的差

* 代码详解
1 | int n, a, b, c, maxn, minn; |
习题九:P1909.NOIP2016.普及组.买铅笔

* 代码详解
1 |
|
九、switch分支
1. swtich分支
-
除了if … else条件分支,还有一种 switch … case 分支,用于变量均为等于成立的分支方案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// case 值1 表示 变量名 == 值1,成立的话,执行下面缩进的语句
// break; 表示跳出switch,否则会继续判断后续的case;
// default 相当于 else,在没有满足条件的时候执行,当然,可以省略这个;
switch (变量名) {
case 值1:
执行语句;
break;
case 值2:
执行语句;
break;
case 值3:
执行语句;
break;
...
default:
执行语句;
}
2. 垃圾分类
-
王二狗要下楼倒垃圾,垃圾分类有四种,他到底应该倒哪个桶呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// 垃圾种类
int n;
// 输入提示
cout << "请输入垃圾种类的序号:" << endl;
cout << "1.表示可回收垃圾!" << endl;
cout << "2.表示有害垃圾!" << endl;
cout << "3.表示厨余垃圾!" << endl;
cout << "4.表示其它垃圾!" << endl;
cout << "请输入1-4:";
cin >> n;
// switch分支
switch (n) {
case 1:
cout << "王二狗往可回收垃圾桶倒了垃圾!";
break;
case 2:
cout << "王二狗往有害垃圾桶倒了垃圾!";
break;
case 3:
cout << "王二狗往厨余垃圾桶倒了垃圾!";
break;
case 4:
cout << "王二狗往其它垃圾桶倒了垃圾!";
break;
default:
cout << "你往哪里倒???倒错了吧!";
break;
}
十、for循环.累加和
1. for语句
计算机最大的一个特性就是快速的重复执行有规律的运算,for循环语句 就是做这种事的
1 | for (循环变量初始化;循环条件;循环变量增或减) { |

-
使用 for 循环语句,输出1-10这十个数字:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 输出1-10,每个数字换行
// int i = 1; 循环变量初始化,从1开始
// i <= 10; 循环判断,当i目前小于等于10时,继续执行循环体
// i++;让循环变量进行累加,效果为:i = i + 1,没有这个过程就死循环啦
// cout << i << endl; 循环体,也就是可执行语句的部分
// 流程图文字版如下:
// 第一步:int i = 1;初始化循环变量,这条语句只执行一次
// 第二步:i <= 10; 判断循环条件;
// 第三步:cout << i << endl; 第二步条件成立后,执行这一步,不成立,退出for语句;
// 第四步:i++;增值变量;然后回到第二步继续
// 后续一直循环2,3,4步,直到退出for语句位置;
for(int i=1;i<=10;i++){
cout << i << endl;
}
cout << "退出 for 循环后执行我!";
2. 累加和
-
通过 for 循环 代码将一个月的零花钱保存起来,1号存1块,2号存2块…30号存30块,共存了多少钱。
1
2
3
4
5
6
7
8
9
10
11// 存钱变量
int sum = 0;
// 累加和
for(int i=1;i<=30;i++){
// sum = sum + i;
sum += i;
}
// 输出
cout << sum;
习题十:1700.输出两位数中含2的整数

* 代码详解
1 | // 十位 个位 |
习题十一:1058.求三位数的水仙花数

* 代码详解
1 | // 百 十 个 |
习题十二:1395.小丽找数?

* 代码详解
1 | // 整数 |
十一、for嵌套
1. for嵌套
for嵌套是什么意思?for语句的循环体再执行一个for语句吗?没错!
1 | // 先来个简单的需求,完成下列图形 |
1 | // 首先,开启纬度思想,一维即:一行一条线;二维则:多行多列是个面 |
2. 九九乘法表
利用 for循环 嵌套,实现一个不重复的 九九乘法表
1 | // 第一步:先考虑1x1=1...1x9=9 这一列 |
习题十三:1492.空心正方形

* 代码详解
1 | // 正方形边数 |
习题十四:1006.打印星号三角形

* 代码详解
1 | // 行数 |
习题十五:1019.求1!+2!+…+N!

* 代码详解
1 | // 整数n, 总和sum |
习题十六:1519.求1~n中每个数的因子

* 代码详解
1 | // 整数n |
十二、变量作用域.退出循环
1. 变量作用域
变量作用域分为局部和全局,在之前的解题中存在不同位置,效果也不尽相同;
1 | // 首先,函数还没学过,不考虑 |
1 | // 这里int i属于for体内的局部变量i |
2. break 退出
break 的作用是在循环体内,可设置条件来退出这个循环;
1 | // break退出 |
3. continue 退出
continue 的作用是在循环体内,可设置条件来退出当前这次循环,然后继续执行下一次循环;
1 | // continue退出 |
习题十七:P1075.NOIP2012.普及组.质因数分解

* 代码详解
1 | // 质数 = 素数,只能被1和本身整除 |
习题十八:P5725.求三角形

* 代码详解
1 | // n |
习题十九:P2669.NOIP2015.普及组.金币

* 代码详解
1 | // k天数, coin金币, day当前累计天 |
十三、while和do while循环
1. while
while 循环相当于 for 循环,可以不用计数器,需要先进行条件判断,也可设置死循环
1 | // 死循环:条件是1或者true,让它永远成立即可 |
2. do while
do while 循环相当于 while 循环,可以将条件判断至于循环体下方,让其无条件先循环一次
1 | // 不管条件是否满足,至少要执行一次循环体 |
习题二十:1062.求落地次数

* 代码详解
1 | // m高度,审题有0.5,所以是浮点型 |
习题二十一:1261.韩信点兵

* 代码详解
1 | // 人数 |
十四、短除法.新式拆位
1. 短除拆位
之前我们拆位使用了整除+求余的方式,但对于不确定位数的整数就会捉襟见肘
1 | // 要求输入三至五位整数 |
习题二十二:1750.有0的数

* 代码详解
1 | int n, count = 0; |
习题二十三:P1307.NOIP2011.普及组.数字反转

* 代码详解
1 | // n原数,f新数 |
习题二十四:P1980.NOIP2013.普及组.计数问题

* 代码详解
1 | int n, x, count = 0; |
习题二十五:P1089.NOIP2004.提高组.津津的储蓄计划

* 代码详解
1 | // money钱, cost花销, mather妈 |
十五、简单穷举
1. 穷举说明
穷举即枚举,我们会在下一套课程中讲解 暴力枚举,那么现在先简单的了解下
- 其实,在之前循环课程中,我们经常使用穷举法,只是没有挑明:
- 通过不断循环,让大量的值进行比对验证,得出想要的结果;
2. 买公园门票
1 | // 假设只有一个小孩,成人拥有的票钱 = 40 - 3 |
习题二十六:1025.兑换硬币

* 代码详解
1 | // 100分, 累计count |
十六、批量存储.一维数组
1. 数组声明
数组分为:一维、二维、多维,大部分情况下只用一维,少量二维,多维很少
-
变量只能存储一条数据,数组可以存储多条数据;
-
比如我要声明一个可以存放10条数据数组:
- 格式为:类型名 数组名[表达式] 注:[] 可以是数字,也可以是a-1的运算;
1
2// 声明可以存放10条数据的数组,数组里的值(或叫元素)为整数
int a[10];a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] 78 59 66 12 9 128 98 73 52 76 -
从上述的数组数据结构图中,总结几点:
- int a[10]:表示声明一个可以存放10条整数的数组a;
- 其中[0~9],我们称为下标,它的范围是0-9之间;
- 对某一个下标进行赋值取值,可以是:a[5] = 128;
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 对数组a下标5,也就是第6个位置赋值
a[5] = 128;
// 输出123
cout << a[5];
// 没有赋值的数组会随机出现不同值
cout << a[3];
// 当然这里有一个目前还没有学习的概念:全局变量和局部变量
// 如果把int a[10]放在int main()外部,就是全局,那么不赋值默认就是0
// 如果是局部变量:没有赋值的还有可能默认0,我们可以用循环查看
for(int i=0;i<=19;i++){
printf("a[%d]=%d\n", i, a[i]);
} -
第二种数组的赋值方式,采用花括号对声明的数组直接赋值:
1
2
3
4
5
6
7
8
9
10
11// 花括号直接赋值
int a[10] = {78, 59, 66, 12, 9, 128, 98, 73, 52, 76};
// 通过循环逐步输出,注意,i从0开始,i<=9或<10
for(int i=0;i<=9;i++){
printf("a[%d]=%d\n", i, a[i]);
}
// 如果你设置了a[20],但{}里只有10个数据,则会用整数0填充
for(int i=0;i<=19;i++){
printf("a[%d]=%d\n", i, a[i]);
} -
如果不确定赋值的个数,可以采用动态方案赋值:
1
2// 但这样,就无法得知长度了;需要通过以后学习的sizeof()函数来获取,先不深入探讨
int a[] = {1, 2, 3, 4, 5} -
至于无法一开始初始化指定值,又怕未赋值导致随机值,可以先初始化零;
1
2
3
4// 初始化0:方案一
int a[10] = {};
// 初始化0:方案二
int a[10] = {0};
2. 下标越界
什么是下标越界:声明时,超过了指定的范围就是下标越界,规定:不要越界;
-
下标越界,有些平台会报异常,有些不报错(这种最要命,程序没错,数据错了检查不出来)
-
所以,不要越界;
-
比如,你int a[10],你赋值时就初始化时,就无法对a[20]赋值,导致随机数字;
1
2int a[10] = {0};
cout << a[12];
习题二十七:1153.查找“支撑数”

* 代码详解
1 | // 整型数组,长度100,默认0,废弃a[0],+1 |
习题二十八:1354.拿到某个数的概率

* 代码详解
1 | // 球 |
习题二十九:2029.缺失的数字

* 代码详解
1 | // 数 |
习题三十:P1047.NOIP2005.普及组.校门外的树

* 代码详解
1 | int l, m, a[10001] = {0}; |
十七、二维数组.多维数组
1. 数组声明
所谓的二维数组,就是数组里还有一个数组,类似嵌套循环,多维数组就是数组里的数组里的数组;
-
声明格式:
1
数据类型 数组名[行数][列数] // 就是两层嵌套循环
-
二维数组构建一个矩阵表格:
a[0,0] -> 78 a[0,1] -> 102 a[0,2] -> 44 a[1,0] -> 92 a[1,1] -> 165 a[1,2] -> 92 a[2,0] -> 67 a[2,1] -> 278 a[2,2] -> 39 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// 上面的构建,从0开始的,也可以和之前废弃0从1开始
int a[3][3];
// 硬赋值
a[0][0] = 78;
a[0][1] = 102;
a[0][2] = 44;
a[1][0] = 92;
a[1][1] = 165;
a[1][2] = 95;
a[2][0] = 67;
a[2][1] = 278;
a[2][2] = 39;
// 二维数组较好理解的初始化,内嵌的花括号表示一行,逗号结束表示换行
int b[3][3] = {{78, 102, 44}, {92, 165, 95}, {67, 278, 39}}
// 二维数组本质也是一维数组,可按照一维方式赋值
int b[3][3] = {78, 102, 44, 92, 165, 95, 67, 278, 39};
// 嵌套循环输出
// 输出矩阵为:
// 第一轮:a[0][0] a[0][1] a[0][2]
// 第二轮:a[1][0] a[1][1] a[1][2]
// 第三轮:a[2][0] a[2][1] a[2][2]
for(int i=0;i<=2;i++){
for(int j=0;j<=2;j++){
printf("%5d", a[i][j]);
}
printf("\n");
}
2. 多维数组
多为数组,三维:数组里的数组里的数组,不用理解到其它学科的纬度
1 | // 题外话:不用理解成几何里三维立体,四维超立体,或天文里的四维时空,没那么复杂 |
习题三十一:1272.郭远摘苹果

* 代码详解
1 | int n, m, a[11][11] = {0}; |
习题三十二:1384.靶心数

* 代码详解
1 | int n, m, a[101][101] = {0}; |
习题三十三:P5731.蛇形方阵

* 代码详解
1 | int n, a[10][10] = {0}; |
习题三十四:P5732.杨辉三角

* 代码详解
1 | // 杨辉三角形特性 |
习题三十五:P5729.工艺品制作

* 代码详解
1 | // 三维 |
十八、函数.参数.返回值.常量
1. 自定义函数
函数或叫自定义函数,是用户自己定义的一种函数,适用于将大量重复的代码进行封装调用
-
自定义函数说明:
- 每个程序都在用函数,比如 int main() 这是主函数,程序在这里自动执行;
- int main() 中, int是返回类型,自然也会有其它类型,甚至无返回类型void;
- 函数末尾除了void类型,一般都会有一个return 返回对应类型;
- 函数名也遵循变量原则;
- 用户自定义创建的函数,无法像主函数 main() 那样自动执行,需要被调用自行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 创建一个无返回值的自定义函数,通过调用执行
// 比如重复输出10组星号三角形
// 星号三角
void star() {
for(int i=1;i<=3;i++){
for(int j=1;j<=i;j++){
cout << "*";
}
cout << endl;
}
}
int main() {
for(int i=1;i<=10;i++){
star();
}
return 0;
}
2. 参数和返回值
函数中有两个重要的概念:参数和返回值,用于更加灵活的使用函数;
-
参数:
- 形参(形式参数),在定义函数时定义的变量(类似变量声明,可直接赋值作为初始值);
- 实参(实际参数),在调用函数时传递的值(类似赋值,直接给形参变量赋值);
- 定义了形参,实参需要一一对应传递赋值,否则出错;
- 如果形参设置了默认值,则可以省略,一般定义默认值的形参在最后;
- 有默认值的形参,如果被实参传递,则覆盖默认值;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// 带参数的void类型函数
// 控制输出的星数
// num:每行个数
// line:行数
// def:显示的字符
void star(int num, int line, string def = "*") {
for(int i=1;i<=line;i++){
for(int j=1;j<=num;j++){
cout << def;
}
cout << endl;
}
// 特别注意:函数里声明的变量num,line,def,i,j在star函数体外无法识别
}
int main() {
// 调用,并传参
star(5, 5);
star(3, 3, "@");
return 0;
} -
返回值:
- void 类型 是无返回值的,上面已经研究过;
- 需要返回值的类型:比如 int 、float 、string 等;
- 为什么要返回值?因为可以把函数当成一个变量,参与到主函数程序中的运算中;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 计算一个圆的面积和周长的和
// 圆的面积:π * r * r
float area(int r) {
float pi = 3.14;
return pi * r * r;
}
// 圆的周长:π * r * 2
float circ(int r) {
float pi = 3.14;
return pi * r * 2;
}
int main() {
// 输入半径r
int r;
cin >> r;
// 计算面积+周长的和
cout << area(r) + circ(r);
return 0;
}
3. 常量概念
之前一直在使用变量,即:可以改变的量;而常量是相对的产物,即:定义后就不可改变的量;
-
常量:
- 语法多种,推荐一种即可:const 类型 常量名 = 值;
- const int A = 10; (这里的A为常量名,推荐用大写,以区别变量)
- 常量是不可改变的量,定义之后无法再次赋值,所以定义时就必须初始化;
- 为何要使用常量,有一些值是固定的,比如π,如果不小心改变了,语法上不报错就非常要命;
- 为何要大写常量名,当一段程序有几十上百量时,常量变量识别度变差,故约定大写;
1
2
3
4
5
6
7
8
9
10
11
12// 创建一个常量PI
const float PI = 3.14;
// 圆的面积:π * r * r
float area(int r) {
return PI * r * r;
}
// 圆的周长:π * r * 2
float circ(int r) {
return PI * r * 2;
} - 语法多种,推荐一种即可:const 类型 常量名 = 值;
习题三十六:1512.甲乙的年龄

* 代码详解
1 | // 1. 甲乙两者年龄只和是两位数 |
1 | // 判断质数 |
习题三十七:1862.友好数

* 代码详解
1 | // 求约数和 |
习题三十八:P5737.闰年展示

* 代码详解
1 | // 之前学习过除了函数的变量作用域 |
十九、P5739.计算阶乘.递归入门

* 代码详解

1 | // 什么是递归?即:通过函数自我执行的方式表现出循环的效果 |
习题三十九:1514.数根

* 代码详解
1 | // 树根 |
习题四十:1223.汉诺塔的移动次数

* 代码详解
1 | // 1. 移动只能一块一块移动 |
习题四十一:P5743.猴子吃桃

* 代码详解
1 | // 1. 每一天吃当前数量的一半+1个 |
习题四十二:1148.数数小木块

* 代码详解
1 | // 先硬算,然后找规律 |
二十、常用内置函数
1. 数学函数
1 |
|
2. 比较函数
1 | // 取最小值 |
习题四十三:P5735.距离函数

* 代码详解
1 | // 用函数减少重复 |
习题四十四:1253.寻找肇事司机

1. 代码详解
1 |
|
习题四十五:P5736.质数筛

* 代码详解
1 | // 判断质数 |
二十一、字符与ASCII码
1. 字符
字符类型,即:char 类型 或 C 风格字符串,可以存储字符或字符串的类型;
-
字符类型说明:
-
强调一下:char 类型 不是 string,string是声明的字符串,可以放一串字符;而char,只能放一个;
- 例:char a = ‘A’ , 1. 只能存一个字符; 2. 必须是单引号包含;
-
如何表示字符串?可以用字符数组来表示:
- char a[5] = “hello”; 1. 这是错的,需要预留一位存储\0(空字符null)来表示结束 ;
- char a[6] = “hello”; 2. 这是对的,此时可以用双引号来表示字符串;
- cout << a; 3. 直接输出即可,无须数组式的循环逐个输出;
a[0] a[1] a[2] a[3] a[4] a[5] h e l l o \0 1
2
3
4
5
6//char a = 'A';
//cout << a;
// 5位不够,需要预留一位存储\0(空字符null)来表示结束
char a[6] = "hello";
cout << a; -
初始化声明方法和普通数组差不多:
1
2
3
4
5
6
7
8
9// 初始化字符数组
char a[6];
// 初始化并直接赋值
char b[6] = {"hello"};
// 初始化并赋值初始值
char c[6] = {0};
// 动态初始
char d[] = {"world"};
-
2. ASCII码
ASCII码,即:美国标准信息交换代码;用于和计算机数据通信;
- 码表:

-
通过上述表查阅到:小写a的十进制编码为97,然后逐步递增。大写的A是65,往后逐步递增;
-
什么是十进制,ASCII码到底如何和计算机通信,解决了啥问题?自己百度查阅,我们只关注答题啊;
1
2
3
4
5
6
7
8
9// 字符型a
char a = 'a';
// 输出它的十进制,即整型数值
cout << int(a);
// 整型数值65
int b = 65;
// 输出它的字符
cout << char(b);
习题四十六:1971.大小写转换

* 代码详解
1 | char a; |
习题四十七:P5733.自动修正

* 代码详解
1 | char a[110] = {0}; |
二十二、cstring头和字符函数
1. sizeof操作符
字符数组是如何获取它的长度,比如占用多少,或者有多少个字符?之前的题目,都只是判断\0结束
-
sizeof:
-
它可以返回一个字符数组所占的内存字节数(字节数理解为:数组分配的一个个小格子)
-
比如 : char a[10] = “hello” , 它占用了多少?
1
2
3
4
5
6
7// 占用10个字节,{"hello"} 和 {'h','e','l','l','o'}; 都一样
char a[10] = "hello";
cout << sizeof(a);
// 占用6个字节,不定式,末尾\0占一个
char a[] = "hello";
cout << sizeof(a); -
所以,想用 sizeof 操作符 来 获取字符个数,其实并不方便。当然,用 a[] 这种 ,然后 - 1也可以。
-
2. cstring头
cstring是 C 标准库头文件, 包含了一些 C 风格字符串的类型和函数;
-
基本使用:
-
首先要引入 cstring : #include
1
2
3
using namespace std; -
使用 strlen() 函数 来获取 字符数组的长度:
1
2
3
4
5// cstring下的strlen函数获取
// 并不会统计占用,也不会统计结束符
// 结果为:5
char a[10] = "hello";
cout << strlen(a); -
使用 strcpy() 和 strncpy() 函数赋值字符数组:
1
2
3
4
5
6
7
8
9
10
11
12
13// 无法直接复制
// char b[20] = a;
// cout << b;
// strcpy复制字符数组
char b[20];
strcpy(b, a);
cout << b;
// strncpy复制指定个数
char c[20];
strncpy(c, a, 3);
cout << c; -
使用 strcat() 和 strncat() 函数,连接字符数组:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 连接两个字符数组
char a[20] = "hello";
char b[10] = ", world!";
// 函数本身会返回连接后的字符串
// 参数1:被添加的字符数组;
// 参数2:添加的字符数组;
cout << strcat(a, b) << endl;
// a被添加了,所以它增加了字符
cout << a << endl;
// b不变
cout << b << endl;
// 连接部分字符数组
char a[20] = "hello";
char b[10] = ", world!";
cout << strncat(a, b, 5) << endl;
cout << a << endl;
cout << b << endl; -
使用 strchr() 和 strstr() 函数,来实现字符数组查找:
1
2
3
4
5
6
7// 查找字符在数组中的位置
char a[20] = "hello, world!";
// 获取第一次查询到的字符位置,并往后输出字符
cout << strchr(a, 'o');
// 获取到底是第几个位置
cout << strchr(a, 'o') - a + 1;1
2
3
4// 查询一串字符在数组中的位置
char a[20] = "hello, world!";
cout << strstr(a, "or");
cout << strstr(a, "or") - a + 1; -
更多 cstring 旗下的函数:https://www.apiref.com/cpp-zh/cpp/header/cstring.html
-
二十三、string字符串.常用函数
1. string
string是标准模板库 STL 中提供处理字符串的工具类型,可以直接赋值使用,无须设置数组;
-
字符串类型:
-
可以直接赋值,无须数组化,但本身又是数组;
-
string是弹性长度,根据你赋值的内容自动伸缩,无须考虑赋值越界问题;
1
2
3
4
5
6
7
8// 字符串需双引号
string s = "hello!";
cout << s;
// string本身也是数组
cout << s[0];
cout << s[3];
cout << s[5];
-
2. 常用函数
字符串类型,有非常多的实用函数工具,这里把最最常用的罗列出来,后续课程逐步补充
-
首先,字符串类型 string 本质是一个类(和之前的类型有所区别),它函数语法是类形式的语法:
- 语法结构为:字符串变量.函数() ,这里的 函数(),我个人喜欢读成 方法();
- 也就是:字符串变量.方法() ,在使用这些方法时,需要 include
; - 当然,我这里使用如下方法并没有引入
也可以使用,可见已被隐式引入;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42// 字符串
string s = "hello";
// 获取字符串长度size()或length()方法
cout << s.size();
cout << s.length();
cout << s.max_size(); // 获取最大字符数
// 拼接方法append(),在s后面添加字符串
s.append(", world!");
cout << s;
// 拼接字符串,直接用+号也能实现
s += ", world!";
cout << s;
// 插入字符(一个),push_back()末尾插入
s.push_back('a'); // 一个字符单引号
cout << s;
// 指定位置插入字符或字符串:insert()
s.insert(3, "@@@"); // 字符串形式,两个参数:位置和字符串
cout << s;
s.insert(3, 4, '#'); // 字符形式,三个参数:位置、个数、单个字符
cout << s;
// 查找字符串中是否包含某个字符:find()
// 不存在返回:-1,存在返回:位置
cout << s.find("ll"); // 只有一个参数时
// 参数2,从第几个位置查找,自然找不到,会返回一个超大的数
// 超大数不好判断没找到,一般是最好返回-1
// 但由于find()本身返回的是无符号整数,即:没有负数,所以无法返回-1
// 直接用 int 转换下即可
cout << int(s.find("ll", 3)) << endl;
// 或赋值方案
int index = s.find("11", 3);
cout << index;
// 字符串截取:substr
cout << s.substr(2); // 从第2个位置截取到最后
cout << s.substr(2,2); // 从第2个位置截取2个
二十四、string.char.int的相互转换
1. char转int
其它现代语言数据类型转换都比较方便,而C++这种语言机制导致转换起来较为麻烦
-
char字符转int:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 先抛出问题:string数字转int,常规方法int转不了
string x = "97";
cout << x + 1; // 语法错误,无法相加
cout << int(x) + 1; // 语法错误,无法转换
// 字符 char转ascii码
char y = 'a';
cout << y; // 输出字符a
cout << int(y); // 输出ascii码97,所以,用int转换char字符,只会得到ascii码
// 字符数字 char转int
char z = '8';
cout << int(z); // 输出的是56,得到的是ascii码
cout << z - '0'; // 输出的是8,可以得到整型8
cout << z - '0' - 1; // 输出的是7,为了验证是不是int,减1便知
cout << atoi(&z); // 输出的是8,&表示z变量的引用地址(指针),不用理解,记住语法即可
// 关于指针和引用地址,会在后续课程中专门篇幅讲解(不是本套),目前都是有意避开,避不开的强记
2. string转int
将 string 转换成 int 的思路:就是先让 string 变成 char 的引用,然后用 atoi() 函数转换
-
string字符转int:
1
2
3
4
5
6
7
8
9// string转int
string k = "123";
// 先转换到char的指针,使用c_str()函数就是这个意思
// 然后再用atoi函数包裹转成int
cout << atoi(k.c_str()) + 1; // 124
// 当然还提供了直接转换的函数stoi
string p = "456";
cout << stoi(p);
二十五、读入一行.fgets.getline函数
1. getline()函数
在读入字符串时,遇到换行和空格,它是认为下一次 cin 读入,这给我们编码带来一些麻烦
-
getline()读入一整行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 先抛出问题,假设s1输入=> hello world!
string s1;
cin >> s1;
cout << s1; // 结果为hello,空格后的字符串会理解为下一次cin
// scanf也不行
string s2;
scanf("%s", &s2); // 直接报错,无法使用
cout << s2;
// scanf单字符输入
char a;
scanf("%c", &a); // 单字符输入,不管输入多少,得到1个字符
cout << a;
// scanf字符数组输入,字符数组本身是引用地址,无须&前缀
char s[10];
scanf("%s", s); // 输入多少,输出多少,可是遇到空格就没了
cout << s;1
2
3
4
5// getline(cin, str) 参数1:固定cin,参数2:输入的字符串变量
// getline()函数 适用于 string类型
string s;
getline(cin, s); // 输入 hello world! 不会被空格断掉
cout << s;
2. fgets()函数
对于字符数组,我们可以采用 fgets() 函数读入一整行
-
fgets()读入一整行:
1
2
3
4
5
6
7// 字符数组s
char s[20];
// 参数1:要存储的字符数组
// 参数2:限定最大读入长度,防止越界
// 参数3:固定参数,表示标准输入
fgets(s, sizeof(s), stdin);
cout << s; -
cin.getline()读入一整行:
1
2
3
4// 和fgets()函数类似
char s[20];
cin.getline(s, sizeof(s));
cout << s;
习题四十八:1478.出现次数最多的小写字母

* 代码详解
1 | char s[110]; |
习题四十九:P1125.NOIP2008.提高组.笨小猴

* 代码详解
1 | char s[110]; |
习题五十:1134.国王的魔镜

* 代码详解
1 | // 判断是否回文 |
习题五十一:P5015.NOIP2018.普及组.标题统计

* 代码详解
1 | string s; |
习题五十二:1012.我是第几个单词

* 代码详解
1 | string s; |
习题五十三:P1308.NOIP.普及组.统计单词数

* 代码详解
1 | // 转成小写 |
习题五十四:1113.隐藏的最大整数

* 代码详解
1 | string s; |
二十六、结构体概念入门
1. 基本格式
结构体:即一组变量的聚合体,可以将非同类型的数据绑定成一体的这么个东西
- 结构体语法:
1 | // 结构体类型创建,并对内部变量直接赋初始值 |
1 | // 初始化交给变量声明 |
2. 数组
结构体数组:如果要实现多组结构体数组,和普通数据使用方法一样,结合结构体语法即可
-
数组语法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14struct grade {
string name;
int age;
char gender;
};
int main() {
// 不省略struct,提高可读性
struct grade s[3] = {{"张三", 15, 'A'}, {"李四", 14, 'B'}, {"王五", 13, 'A'}};
// 输出结构体数组第一条
cout << s[0].name << " " << s[0].age << " " << s[0].gender;
return 0;
}
习题五十五:P5744.培训

* 代码详解
1 | // 学员信息 |
习题五十六:P5740.最厉害的学生

* 代码详解
1 | struct info { |
习题五十七:1953. 新生舞会

* 代码详解
1 |
|





