- bitworld 的博客
GESP复习手册-1级
- @ 2026-1-16 15:57:03
第1章 计算机基础知识
1.1 计算机发展史
计算机的发展是人类科技史上的重要里程碑,其历程大致可分为以下几个关键阶段:
1.1.1 早期构想阶段(19世纪)
- 查尔斯·巴贝奇:
- 英国数学家、发明家
- 提出差分机和分析机的构想
- 分析机:
- 具备现代计算机五大基本部件:输入设备、输出设备、存储器、运算器、控制器
- 被视为现代计算机的雏形
1.1.2 电子管时代(20世纪40年代)
- ENIAC(1946年):
- 全称:Electronic Numerical Integrator and Computer
- 世界上第一台通用电子数字计算机
- 发明人:约翰·莫奇利和约翰·埃克特(美国)
- 特点:体积庞大(30吨)、使用1.8万个电子管、运算速度5000次/秒
- 意义:开启了电子计算机时代
- 中国第一台通用数字电子计算机:
- 103机(1958年)
- 研制单位:中国科学院计算技术研究所
1.1.3 计算机各代特点对比表
| 代次 | 时间 | 主要元件 | 特点 | 代表机型 |
|---|---|---|---|---|
| 第一代 | 1946-1957 | 电子管 | 体积大、耗电多、速度慢 | ENIAC、EDVAC |
| 第二代 | 1958-1964 | 晶体管 | 体积减小、可靠性提高 | IBM 1401 |
| 第三代 | 1965-1970 | 中小规模集成电路 | 体积更小、功耗降低 | IBM System/360 |
| 第四代 | 1971至今 | 大规模/超大规模集成电路 | 微型化、智能化、网络化 | 个人计算机 |
1.1.4 中国超级计算机成就
| 计算机名称 | 特点 | 重要成就 |
|---|---|---|
| 神威·太湖之光 | 中国自主研制,使用国产处理器 | 2016-2017年多次在TOP500中排名第一 |
| 天河系列 | 中国自主研发的超级计算机系统 | 天河二号曾多次获得TOP500第一 |
| 曙光系列 | 中国高性能计算机代表 | 广泛应用于科学计算和工程领域 |
1.2 人工智能的历史
1.2.1 诞生期(1950s)
- 1950年:图灵发表《计算机器与智能》,提出"图灵测试"
- 1956年:达特茅斯会议,正式确立"人工智能"学科名称
- 早期成就:能够解决代数问题、证明几何定理
1.2.2 第一次AI寒冬(1960s-1970s)
- 原因:
- 技术限制:计算机性能不足
- 资金减少:未达到预期效果
- 理论瓶颈:无法解决复杂问题
1.2.3 专家系统时代(1980s)
- 专家系统:
- 模仿人类专家解决问题的系统
- 应用领域:医疗诊断、金融分析
- 第二次AI寒冬(1987-1993):
- 成本高昂、维护困难
- 应用范围有限
1.2.4 现代AI突破(21世纪)
- 推动技术:
- 大数据
- 云计算
- 深度学习
- 里程碑事件:
- 2012年:深度学习在ImageNet图像识别比赛中取得突破
- 2016年:AlphaGo击败李世石,引发全球关注
- 2018年:GPT系列模型开始发展
- 应用领域:
- 语音识别(Siri、小爱同学)
- 图像识别(人脸识别、自动驾驶)
- 自然语言处理(机器翻译、智能客服)
1.3 计算机领域的代表人物
1.3.1 代表人物对比表
| 人物 | 国籍 | 称号 | 主要贡献 | 相关荣誉/纪念 |
|---|---|---|---|---|
| 艾伦·图灵 | 英国 | 计算机科学之父 人工智能之父 |
1. 提出图灵机概念 2. 设计图灵测试 3. 二战期间破解德国密码 |
图灵奖(计算机界诺贝尔奖) |
| 冯·诺依曼 | 匈牙利/美国 | 现代计算机之父 | 提出冯·诺依曼体系结构 (存储程序概念) | 现代计算机基础架构 |
| 查尔斯·巴贝奇 | 英国 | 计算机先驱 | 设计差分机和分析机 | 分析机被视为计算机雏形 |
| 戈登·摩尔 | 美国 | 摩尔定律提出者 | 摩尔定律:集成电路晶体管数量每18-24个月翻倍 | 英特尔公司创始人之一 |
| 丹尼斯·里奇 | C语言之父 | 1. 发明C语言 2. 开发Unix操作系统 |
影响深远,C语言至今广泛应用 | |
| 姚期智 | 中国/美国 | 计算机科学家 | 计算理论、密码学贡献 | 首位华人图灵奖得主(2000年) |
| 比尔·盖茨 | 美国 | 微软创始人 | 推动个人计算机软件发展 | Windows操作系统 |
| 史蒂夫·乔布斯 | 苹果创始人 | Macintosh、iPhone、iPad等创新产品 | 改变人机交互方式 |
1.3.2补充知识点:
- 图灵奖:
- 设立时间:1966年
- 设立机构:美国计算机协会(ACM)
- 别称:"计算机界诺贝尔奖"
- 首位华人获奖者:姚期智(2000年)
- 冯·诺依曼体系结构五大部件:
- 运算器
- 控制器
- 存储器
- 输入设备
- 输出设备
1.4 计算机硬件系统
1.4.1 计算机系统的组成
graph LR
subgraph "硬件系统"
subgraph "主机"
CPU[CPU<br>运算器+控制器]
MEM[内存]
end
subgraph "外部设备"
IN[输入设备]
OUT[输出设备]
STOR[外存储器]
end
end
subgraph "软件系统"
SYS[系统软件]
APP[应用软件]
end
计算机系统[计算机系统] --> 硬件系统
计算机系统 --> 软件系统
%% 数据流向示意
IN --> MEM
MEM --> CPU
CPU --> MEM
MEM --> OUT
MEM <--> STOR
%% 样式
style 计算机系统 fill:#f9f,stroke:#333,stroke-width:2px
style 硬件系统 fill:#e6f2ff,stroke:#333
style 软件系统 fill:#e6ffe6,stroke:#333
1.4.2 冯·诺依曼结构
计算机硬件系统由五大部分组成:
- 运算器:执行算术运算和逻辑运算
- 控制器:指挥控制中心,协调整个电脑有序工作
- 存储器:保存各类程序的数据信息
- 输入设备:外界向计算机传送信息的装置
- 输出设备:把计算机处理过的信息以人们认识的形式表示出来
1.4.3 中央处理器(CPU)
- 作用:计算机的"大脑",负责运算和控制
- 组成:
- 控制器:指挥控制中心
- 运算器:执行算术和逻辑运算
- 寄存器:临时存储数据,提高速度
- 常见CPU品牌:Intel、AMD、国产龙芯
1.4.4 存储器
| 类型 | 特点 | 作用 | 常见形式 | 是否临时 |
|---|---|---|---|---|
| 内存 | 临时存储器,速度快 | 存放当前运行的程序和数据 | RAM、ROM、Cache | 是 |
| 外存 | 永久存储器,速度慢 | 长期保存数据和程序 | 硬盘、U盘、光盘 | 否 |
1.4.5 输入设备
- 输入设备(向计算机传送信息):
- 基本:键盘、鼠标
- 图像:扫描仪、摄像头、手写板
- 声音:麦克风
- 专用:游戏手柄、条码扫描器、传感器
1.4.6 输出设备
- 输出设备(计算机向外界输出信息):
- 显示:显示器、投影仪
- 打印:打印机、3D打印机
- 声音:音箱、耳机
- 其他:绘图仪
1.4.7 计算机主机
- 组成:CPU + 内存储器
- 外设:输入设备、输出设备、外存储器
1.4.8 数据存储单位
- 最小单位:位(bit,简写为b),可以是0或1
- 基本单位:字节(Byte,简写为B),1B = 8b
- 换算关系:以1024为进率
| 单位 | 英文 | 简称 | 换算关系 | 示例 |
|---|---|---|---|---|
| 位 | bit | b | 最小单位,0或1 | 1b |
| 字节 | Byte | B | 1B = 8b | 字母"A"占1B |
| 千字节 | Kilobyte | KB | 1KB = 1024B | 一页文字约3KB |
| 兆字节 | Megabyte | MB | 1MB = 1024KB | 一首MP3约4MB |
| 吉字节 | Gigabyte | GB | 1GB = 1024MB | 一部电影约1GB |
| 太字节 | Terabyte | TB | 1TB = 1024GB | 大型数据库 |
1.5 计算机软件系统
1.5.1 软件系统分类
| 类型 | 作用 | 示例 |
|---|---|---|
| 系统软件 | 管理和控制计算机所有软、硬件资源 | 操作系统、语言处理程序、数据库管理系统 |
| 应用软件 | 满足用户特定需求 | 聊天软件、办公软件、游戏软件、教育软件 |
1.5.2 操作系统
- 三大功能:
- 硬件管理:CPU调度、内存分配、设备驱动
- 软件支持:为应用程序提供运行环境
- 用户接口:命令行、图形界面
- 常见操作系统:
- PC系统:Windows、macOS、Linux、Unix
- 移动系统:Android、iOS、HarmonyOS
- 国产系统:华为鸿蒙(HarmonyOS,2019年发布)、统信UOS
1.5.3 编程语言处理程序
- 编译器:将高级语言转换为机器语言
- 解释器:逐行翻译执行程序
- 汇编器:将汇编语言转换为机器语言
1.6 计算机语言
1.6.1 编程语言发展历程
| 类型 | 时期 | 特点 | 缺点 |
|---|---|---|---|
| 机器语言 | 1940s | 二进制代码,CPU直接执行 | 难记忆、难编写、难调试 |
| 汇编语言 | 1950s | 使用助记符,需汇编器转换 | 依赖硬件、可移植性差 |
| 高级语言 | 1950s至今 | 接近自然语言,易学易用 | 需编译或解释 |
1.6.2 高级语言分类
- 面向过程:C、Pascal、Fortran
- 面向对象:C++、Java、Python、C#
- 脚本语言:JavaScript、PHP、Python
1.6.3 高级语言的执行过程
源代码 → 编译器 → 目标代码 → 链接器 → 可执行文件 → CPU执行
关键点:
- 高级语言不能直接在CPU上执行
- 必须经过编译或解释
- C++属于编译型语言
1.7 计算机的分类
1.7.1 按性能和规模分类
| 类型 | 特点 | 应用领域 | 示例 |
|---|---|---|---|
| 超级计算机 | 运算速度极快(每秒万亿次以上) | 气象预报、核能研究、基因分析 | 神威·太湖之光、天河二号 |
| 大型计算机 | 高可靠性、支持多用户同时使用 | 银行、证券、大型企业数据中心 | IBM Z系列 |
| 小型计算机 | 性能适中,价格较低 | 中小型企业、学校 | IBM Power系列 |
| 微型计算机 | 个人使用,价格便宜 | 个人办公、学习、娱乐 | 台式机、笔记本电脑 |
| 嵌入式计算机 | 嵌入其他设备,功能专一 | 智能家居、汽车电子、医疗设备 | 单片机、工控机 |
1.7.2 按用途分类
- 通用计算机:可处理多种任务,如个人电脑
- 专用计算机:针对特定任务优化,如ATM机、收银机
- 服务器:为网络中的其他计算机提供服务
- 工作站:高性能计算机,用于专业领域(如CAD设计)
1.7.3 按外形分类
- 台式计算机
- 便携式计算机(笔记本电脑、平板电脑)
- 手持设备(智能手机、PDA)
1.8 计算机的应用
| 应用领域 | 特点 | 实际案例 |
|---|---|---|
| 科学计算 | 处理复杂数学问题,要求高精度 | 天气预报、航天轨道计算、地震模拟 |
| 数据处理 | 处理大量数据,进行统计分析 | 学生成绩管理、银行账户管理、人口普查 |
| 过程控制 | 实时监控和调节生产过程 | 化工生产控制、机器人控制、智能家居 |
| 人工智能 | 模拟人类智能行为 | 语音助手、自动驾驶、智能推荐 |
| 计算机辅助 | 帮助人类完成设计制造任务 | CAD(设计)、CAM(制造)、CAI(教学) |
| 网络通信 | 实现远程信息交换和资源共享 | 电子邮件、视频会议、在线学习 |
| 多媒体应用 | 处理图像、音频、视频 | 电影特效、游戏开发、数字音乐 |
| 教育培训 | 辅助教学和技能培训 | 编程学习平台、虚拟实验室 |
1.8.2 现代计算机应用趋势
- 物联网:万物互联,智能感知
- 云计算:资源共享,按需服务
- 大数据:海量数据,智能分析
- 边缘计算:靠近数据源,实时处理
第2章 程序的输入和输出
2.1 输入输出概述
2.1.1 什么是输入输出
- 输入:从外部设备(键盘、文件等)读取数据到程序中
- 输出:将程序处理的结果显示到外部设备(显示器、文件等)
- 交互:输入输出是程序与用户交互的主要方式
2.1.2学习目标
- ✅ 掌握C++基本输入输出语句
- ✅ 理解整型和浮点型数据的输入输出
- ✅ 能够编写简单的输入输出程序
- ✅ 解决常见输入输出问题
2.1.3 C++输入输出特点
| 特点 | 说明 | 优势 |
|---|---|---|
| 流式I/O | 数据像水流一样传输 | 简单直观 |
| 类型安全 | 自动识别数据类型 | 减少错误 |
| 缓冲区 | 数据先进入缓冲区再处理 | 提高效率 |
2.2 C++语言的输入输出
C++语言提供了输入输出流(I/O流)机制,通过cin和cout对象实现输入输出,这种方法比C语言更简便、安全。
2.2.1 基本框架(必须掌握)
#include <iostream> // 1. 包含输入输出头文件
using namespace std; // 2. 使用标准命名空间
int main() { // 3. 主函数开始
// 程序代码
return 0; // 4. 程序结束
}
2.2.2 输出语句(cout)
基本格式:
cout << 输出项1 << 输出项2 << ... << 输出项n;
详细解析:
cout:标准输出流对象(console output)<<:插入运算符,将数据"插入"到输出流- 输出项:可以是常量、变量、表达式
输出示例对比:
| 代码 | 输出结果 | 说明 |
|---|---|---|
cout << 5; |
5 |
输出整数 |
cout << 3.14; |
3.14 |
输出浮点数 |
cout << 'A'; |
A |
输出字符 |
cout << "Hello"; |
Hello |
输出字符串 |
cout << 2+3; |
5 |
输出表达式结果 |
示例:
int age = 12;
double height = 1.65;
cout << "年龄:" << age << "岁" << endl;
cout << "身高:" << height << "米" << endl;
cout << "年龄和身高的和:" << age + height << endl;
输出结果:
年龄:12岁
身高:1.65米
年龄和身高的和:13.65
2.2.3 输入语句(cin)
基本格式:
cin >> 变量1 >> 变量2 >> ... >> 变量n;
详细解析:
cin:标准输入流对象(console input)>>:提取运算符,从输入流中"提取"数据- 变量:接收输入值的容器
示例:
#include <iostream>
using namespace std;
int main() {
int num1, num2;
double score;
// 连续输入三个值
cin >> num1 >> num2 >> score;
// 输出验证
cout << "整数:" << num1 << " 和 " << num2 << endl;
cout << "浮点数:" << score << endl;
return 0;
}
运行示例:
输入:10 20 98.5
输出:整数:10 和 20
浮点数:98.5
输入特点总结:
- 自动类型转换:根据变量类型转换输入数据
- 空格分隔:用空格、制表符、换行符分隔数据
- 顺序匹配:按顺序将输入值赋给变量
2.3 数据类型与格式控制
2.3.1 整型数据的输入输出
整型数据类型对比:
| 类型 | 字节数 | 取值范围 | GESP使用频率 |
|---|---|---|---|
int |
4 | -2,147,483,648 ~ 2,147,483,647 | ★★★★★ |
short |
2 | -32,768 ~ 32,767 | ★☆☆☆☆ |
long |
4/8 | 根据系统不同 |
示例:
#include <iostream>
using namespace std;
int main() {
int a, b;
// 输入两个整数
cin >> a >> b;
// 计算并输出
int sum = a + b;
int difference = a - b;
int product = a * b;
cout << a << " + " << b << " = " << sum << endl;
cout << a << " - " << b << " = " << difference << endl;
cout << a << " × " << b << " = " << product << endl;
// 整数除法(重要!)
cout << a << " ÷ " << b << " = " << a / b << endl;
return 0;
}
整数除法特性:
int a = 7, b = 2;
int result1 = a / b; // 结果为3(小数部分丢失)
double result2 = a / b; // 结果为3.0(仍然丢失小数部分)
double result3 = (double)a / b; // 结果为3.5(正确方法)
⚠️ GESP考试常见陷阱:
int a = 5, b = 2;
double c = a / b; // c的值是2.0,不是2.5!
2.3.2 浮点型数据的输入输出
浮点型数据类型对比:
| 类型 | 字节数 | 精度 | 推荐程度 |
|---|---|---|---|
float |
4 | 6-7位有效数字 | ★★☆☆☆ |
double |
8 | 15-17位有效数字 | ★★★★★ |
示例:
#include <iostream>
using namespace std;
int main() {
double length, width;
// 输入长方形的长和宽
cin >> length >> width;
// 计算面积
double area = length * width;
// 输出结果
cout << "长方形面积:" << area << endl;
// 浮点数输出特点
double pi = 3.141592653589793;
cout << "圆周率:" << pi << endl; // 默认输出6位有效数字
return 0;
}
浮点数输出特性:
| 代码 | 可能输出 | 说明 |
|---|---|---|
cout << 3.14159; |
3.14159 |
正常输出 |
cout << 314159.0; |
314159 |
省略末尾的.0 |
cout << 0.0000314159; |
3.14159e-05 |
科学计数法 |
2.4 常见问题与注意事项
2.4.1 输入时的常见问题
-
输入顺序错误:
// ❌ 错误示例:先计算后输入 int a, b, sum; sum = a + b; // 错误:a和b还没有值 cin >> a >> b; // ✅ 正确示例:先输入后计算 int a, b, sum; cin >> a >> b; // 先获取输入 sum = a + b; // 再计算 -
变量未初始化:
// ❌ 危险做法:未初始化变量 int a, b; // a和b的值不确定(可能是任意值) cin >> a; // 如果输入失败,b的值不确定 // ✅ 推荐做法:声明时初始化 int a = 0, b = 0; // 初始化为0 cin >> a >> b; // 安全输入 -
输入类型不匹配
// ❌ 危险:输入浮点数到整型变量 int age; cin >> age; // 如果输入"12.5",只会读取12,.5留在缓冲区 // ✅ 安全:根据需要选择合适的类型 double age; // 如果需要小数 cin >> age; // 可以输入12.5
2.4.2 输出时的常见问题
-
忘记换行:
// ❌ 输出结果连在一起 cout << "Hello"; cout << "World"; // ✅ 使用endl或\n换行 cout << "Hello" << endl; cout << "World" << endl; // 或者 cout << "Hello\n"; cout << "World\n"; -
输出格式混乱:
// ❌ 格式混乱,不易阅读 cout << "结果是" << result; // ✅ 添加适当空格和标点 cout << "结果是:" << result << endl; // 更好:清晰标注 cout << "计算结果 = " << result << endl;
2.4.3 GESP考试特别注意事项
-
程序开头必须写:
#include <iostream> using namespace std; -
main函数必须返回0:
int main() { // 代码 return 0; // 不能省略 } -
变量使用前必须定义:
// 错误 sum = a + b; // a和b未定义 int a, b; // 正确 int a, b, sum; cin >> a >> b; sum = a + b;
2.5 知识要点总结
2.5.1 必记知识点
- 头文件:
#include <iostream> - 命名空间:
using namespace std; - 输出对象:
cout,配合<<使用 - 输入对象:
cin,配合>>使用 - 换行方式:
endl或\n
2.5.2 基本语法格式
// 单个输出
cout << "Hello, World!" << endl;
// 多个输出
cout << "a=" << a << ", b=" << b << endl;
// 单个输入
cin >> a;
// 多个输入
cin >> a >> b >> c;
// 混合使用
cout << "请输入两个数:";
cin >> x >> y;
cout << "和是:" << x + y << endl;
2.5.3 常用数据类型(GESP一级)
| 数据类型 | 用途 | 示例 | 输入 | 输出 |
|---|---|---|---|---|
int |
整数 | int age = 12; |
cin >> age; |
cout << age; |
double |
小数 | double score = 98.5; |
cin >> score; |
cout << score; |
char |
字符 | char grade = 'A'; |
cin >> grade; |
cout << grade; |
2.5.4 编程黄金法则(考试必记)
- 先包含,后使用:先写
#include,再写代码 - 先定义,后使用:先定义变量,再使用变量
- 先输入,后计算:先获取输入,再进行计算
- 先计算,后输出:先计算结果,再输出显示
- 有始有终:
main函数以return 0;结束
第3章 变量与数据类型
3.1 变量的定义与概念
变量是程序中用于存储数据的容器,在使用前必须先进行定义,明确其数据类型和名称。
3.1.1 变量的基本概念
- 定义:变量是程序中用于存储数据的容器
- 比喻:变量就像贴有标签的盒子
- 盒子有名称(变量名)
- 盒子有类型(数据类型)
- 盒子可以放东西(数据值)
- 盒子的东西可以更换(重新赋值)
3.1.2 C++中变量的定义
基本格式:
数据类型 变量名;
不同定义方式对比:
| 定义方式 | 语法 | 示例 | 特点 |
|---|---|---|---|
| 单独定义 | 数据类型 变量名; |
int age; |
只定义,不赋值 |
| 定义并初始化 | 数据类型 变量名 = 值; |
int score = 100; |
定义同时赋值 |
| 多个同类型变量 | 数据类型 变量1, 变量2, ...; |
int a, b, c; |
一行定义多个 |
定义示例代码:
// 方式1:单独定义
int age;
double height;
char grade;
// 方式2:定义并初始化
int score = 95;
double pi = 3.14159;
char initial = 'A';
// 方式3:定义多个变量
int x = 1, y = 2, z = 3;
double a, b, c;
3.2 变量的命名规则
变量命名需要遵循一定的规则,以保证程序的可读性和正确性。
3.2.1 命名规则
| 规则 | 说明 | 示例 |
|---|---|---|
| 组成字符 | 只能由字母、数字和下划线组成 | name, _count, student1 |
| 首字符 | 必须以字母或下划线开头,不能以数字开头 | age(正确), _count(正确), 123num(错误) |
| 大小写 | 区分大小写 | age和Age是两个不同的变量 |
| 关键字 | 不能使用C/C++关键字作为变量名 | int, float, if, for等不能用作变量名 |
| 长度限制 | 虽然没有严格限制,但应保持合理长度 | 一般不超过32个字符 |
| 可读性 | 应尽量做到见名知意 | 用age表示年龄,score表示分数 |
3.2.2 合法与非法变量名示例
合法的变量名:
int age; // 表示年龄
float average_score; // 表示平均分
int student_count; // 表示学生数量
double _price; // 以下划线开头
int num1, num2; // 包含数字
非法的变量名:
int 123num; // 错误:以数字开头
float int; // 错误:使用了关键字int
double a+b; // 错误:包含非法字符"+"
int my age; // 错误:包含空格
char 变量; // 错误:包含中文字符
3.2.3 命名风格建议
-
小驼峰命名法:
int studentAge; float averageScore; -
下划线分隔法:
int student_age; float average_score; -
常量使用全大写:
const double PI = 3.14159; const int MAX_SIZE = 100;
3.3 变量的赋值
赋值是给变量赋予具体的值,通过赋值运算符"="来实现。
3.3.1 基本赋值
格式:
变量名 = 表达式;
其中,表达式可以是:
- 常量:直接给定的值
- 变量:其他变量的值
- 运算表达式:包含运算符的表达式
示例:
// 定义变量
int a;
float b;
char c;
// 赋值操作
a = 5; // 将常量5赋值给变量a
int d = 10;
a = d; // 将变量d的值赋值给变量a
a = d + 3; // 将d+3的结果赋值给a
b = 3.14; // 将浮点数赋值给变量b
c = 'A'; // 将字符赋值给变量c
3.3.2 复合赋值
为了简化运算,C++提供了复合赋值运算符。
常见的复合赋值运算符:
| 运算符 | 名称 | 示例 | 等价形式 | 运算结果 |
|---|---|---|---|---|
+= |
加后赋值 | a += 5; |
a = a + 5; |
a增加5 |
-= |
减后赋值 | a -= 3; |
a = a - 3; |
a减少3 |
*= |
乘后赋值 | a *= 2; |
a = a * 2; |
a乘以2 |
/= |
除后赋值 | a /= 4; |
a = a / 4; |
a除以4 |
%= |
取模后赋值 | a %= 3; |
a = a % 3; |
a对3取余 |
示例:
int x = 10;
x += 5; // 等价于 x = x + 5, x的值变为15
x -= 3; // 等价于 x = x - 3, x的值变为12
x *= 2; // 等价于 x = x * 2, x的值变为24
x /= 4; // 等价于 x = x / 4, x的值变为6
x %= 2; // 等价于 x = x % 2, x的值变为0
3.3.3 赋值表达式的值
- 特点:赋值表达式本身也有值,值就是被赋的值
- 应用:可以连续赋值
int a, b, c;
a = b = c = 10; // 从右向左:c=10, b=c, a=b
// 等价于:
c = 10;
b = c; // b = 10
a = b; // a = 10
3.4 数据类型
数据类型决定了变量存储的数据的种类和范围。
3.4.1 基本数据类型
| 类型 | 关键字 | 字节数 | 取值范围 | GESP使用频率 |
|---|---|---|---|---|
| 整数 | int |
4 | -2,147,483,648 ~ 2,147,483,647 | ★★★★★ |
| 长整数 | long long |
8 | -9.2×10¹⁸ ~ 9.2×10¹⁸ | ★☆☆☆☆ |
| 单精度浮点 | float |
4 | ±3.4×10^±38,6-7位精度 | ★★☆☆☆ |
| 双精度浮点 | double |
8 | ±1.7×10^±308,15-17位精度 | ★★★★★ |
| 字符 | char |
1 | -128 ~ 127 或 0 ~ 255 | ★★★★☆ |
| 布尔 | bool |
true(1) 或 false(0) |
★★★☆☆ |
整数类型(整型):
| 类型 | 全称 | 典型大小 | 示例 |
|---|---|---|---|
short |
短整型 | 2字节 | short s = 100; |
int |
整型 | 4字节 | int age = 15; |
long |
长整型 | 4或8字节 | long distance = 1000000L; |
long long |
长长整型 | 8字节 | long long big = 10000000000LL; |
示例:
#include <iostream>
using namespace std;
int main() {
short smallNumber = 100; // 小整数
int age = 15; // 一般整数
long population = 7800000000L; // 较大整数
long long veryBig = 10000000000LL; // 非常大的整数
cout << "short: " << smallNumber << endl;
cout << "int: " << age << endl;
cout << "long: " << population << endl;
cout << "long long: " << veryBig << endl;
return 0;
}
浮点类型(浮点型):
| 类型 | 精度 | 内存 | 示例 | 适用场景 |
|---|---|---|---|---|
float |
6-7位有效数字 | 4字节 | float price = 99.99f; |
对精度要求不高,节省内存 |
double |
15-17位有效数字 | 8字节 | double pi = 3.1415926535; |
一般计算,推荐使用 |
示例:
#include <iostream>
using namespace std;
int main() {
// float类型需要加f后缀
float weight = 65.5f; // 单精度
float temperature = 36.8f;
// double类型(默认)
double pi = 3.141592653589793;
double distance = 384400.0; // 地球到月球距离(公里)
cout << "体重: " << weight << "kg" << endl;
cout << "体温: " << temperature << "°C" << endl;
cout << "圆周率: " << pi << endl;
cout << "地月距离: " << distance << "公里" << endl;
return 0;
}
字符类型:
| 特点 | 说明 | 示例 |
|---|---|---|
| 存储单个字符 | 使用单引号 | char grade = 'A'; |
| 实际存储整数 | 存储ASCII码值 | char a = 65;(等价于'A') |
| 可以进行运算 | 字符可以加减 | char next = 'A' + 1;(得到'B') |
| 转义字符 | 特殊字符表示 | char newline = '\n'; |
示例:
#include <iostream>
using namespace std;
int main() {
char letter = 'A';
char digit = '5';
char symbol = '+';
char newline = '\n';
char tab = '\t';
cout << "字母: " << letter << endl;
cout << "数字字符: " << digit << endl;
cout << "符号: " << symbol << endl;
// 字符运算
char nextLetter = letter + 1; // 'A' + 1 = 'B'
cout << "下一个字母: " << nextLetter << endl;
// 查看ASCII码
cout << "A的ASCII码: " << (int)letter << endl;
cout << "B的ASCII码: " << (int)nextLetter << endl;
return 0;
}
布尔类型:
| 特点 | 说明 | 示例 |
|---|---|---|
| 只有两个值 | true 或 false |
bool isReady = true; |
| 实际存储 | true为1,false为0 |
bool flag = false; |
| 用于条件判断 | if、while等语句 | if (isReady) { ... } |
| 可以输出 | 输出1或0 | cout << isReady; 输出1 |
示例:
#include <iostream>
using namespace std;
int main() {
bool isSunny = true;
bool isRaining = false;
bool hasHomework = true;
cout << "天气晴朗: " << isSunny << endl; // 输出1
cout << "正在下雨: " << isRaining << endl; // 输出0
cout << "有作业: " << hasHomework << endl; // 输出1
// 布尔运算
bool canPlay = isSunny && !isRaining;
cout << "可以出去玩: " << canPlay << endl; // 输出1
// 直接输出true/false(C++中需要设置)
cout << boolalpha; // 设置以true/false形式输出
cout << "天气晴朗: " << isSunny << endl; // 输出true
cout << "正在下雨: " << isRaining << endl; // 输出false
return 0;
}
3.4.2 数据类型的选择原则
- 整数的选择:
- 一般整数使用
int - 很大的整数考虑
long或long long
- 一般整数使用
- 小数的选择:
- 一般小数使用
double(精度更高) - 对内存要求严格时使用
float
- 一般小数使用
- 字符的选择:
- 单个字符使用
char - 多个字符(字符串)使用
string(后续章节介绍)
- 单个字符使用
- 布尔值的选择:
- 逻辑判断结果使用
bool
- 逻辑判断结果使用
3.4.3 数据类型的内存表示
// 各种数据类型的内存占用示例
#include <iostream>
using namespace std;
int main() {
cout << "int类型占用字节数:" << sizeof(int) << endl; // 通常为4
cout << "float类型占用字节数:" << sizeof(float) << endl; // 通常为4
cout << "double类型占用字节数:" << sizeof(double) << endl; // 通常为8
cout << "char类型占用字节数:" << sizeof(char) << endl; // 通常为1
cout << "bool类型占用字节数:" << sizeof(bool) << endl; // 通常为1
return 0;
}
3.5 数据类型转换
3.5.1 隐式类型转换
当不同类型的数据进行运算时,编译器会自动进行类型转换。
转换规则:
| 转换方向 | 说明 | 示例 |
|---|---|---|
| 小→大 | 占字节少的转为占字节多的 | short → int → long |
| 整→浮 | 整数转为浮点数 | int → float → double |
| 低精度→高精度 | 精度低的转为精度高的 | float → double |
示例:
#include <iostream>
using namespace std;
int main() {
int a = 10;
double b = 3.14;
// 隐式转换:int → double
double result1 = a + b; // a先转为double,再相加
cout << "10 + 3.14 = " << result1 << endl;
// 隐式转换:int → double
double result2 = a / b; // a先转为double,再相除
cout << "10 / 3.14 = " << result2 << endl;
return 0;
}
3.5.2 显式类型转换(强制类型转换)
使用类型转换运算符明确指定转换类型。
格式:
(目标类型)表达式
示例:
int a = 10;
int b = 3;
double result;
// 将整数转换为浮点数进行计算
result = (double)a / (double)b; // 结果为3.33333...
// 将浮点数转换为整数(会丢失小数部分)
int c = (int)3.14; // c的值为3
3.6 常量
常量是在程序运行过程中值不会改变的量。
3.6.1 常量的定义
使用const关键字:
const 数据类型 常量名 = 值;
示例:
const double PI = 3.14159; // 圆周率常量
const int DAYS_IN_WEEK = 7; // 一周的天数
const char NEW_LINE = '\n'; // 换行符常量
3.6.2 常量的特点
- 值不可变:一旦定义,就不能再修改
- 必须初始化:定义时必须赋值
- 命名约定:通常使用全大写字母和下划线
3.7 常见错误与注意事项
3.7.1 常见错误
-
变量未初始化就使用:
int a; // 未初始化 cout << a; // 错误:a的值不确定 -
类型不匹配的赋值:
int a = 3.14; // 警告:小数部分被截断 -
使用错误的变量名:
int age = 15; cout << Age; // 错误:应为age,区分大小写 -
变量名与关键字冲突:
int int = 10; // 错误:int是关键字
3.7.2 良好编程习惯
-
定义时初始化:
int count = 0; // 好习惯 float total = 0.0; // 好习惯 -
使用有意义的变量名:
int student_age; // 明确表示学生年龄 double exam_score; // 明确表示考试成绩 -
一行只定义一个变量:
int width; // 更清晰 int height; -
保持变量作用域最小:
- 只在需要的地方定义变量
- 避免定义全局变量
3.8 知识要点总结
3.8.1 核心概念
| 概念 | 说明 | 关键点 |
|---|---|---|
| 变量 | 存储数据的容器 | 必须先定义后使用 |
| 数据类型 | 决定数据的种类和范围 | 选择合适的类型 |
| 变量名 | 标识变量的名称 | 遵循命名规则,见名知意 |
| 赋值 | 给变量赋予值 | 使用"="运算符 |
3.8.2 常用数据类型
| 数据类型 | 用途 | 示例 |
|---|---|---|
int |
存储整数 | int age = 15; |
double |
存储小数 | double pi = 3.14; |
char |
存储单个字符 | char grade = 'A'; |
bool |
存储真假值 | bool is_true = true; |
3.8.3 赋值运算符
| 运算符 | 作用 | 示例 |
|---|---|---|
= |
基本赋值 | a = 5; |
+= |
加后赋值 | a += 3; 等价于 a = a + 3; |
-= |
减后赋值 | a -= 2; 等价于 a = a - 2; |
*= |
乘后赋值 | a *= 4; 等价于 a = a * 4; |
/= |
除后赋值 | a /= 2; 等价于 a = a / 2; |
3.8.4 命名规则要点
- 字母、数字、下划线组成
- 不能以数字开头
- 区分大小写
- 不能使用关键字
- 见名知意
第4章 表达式
4.1 表达式的基本概念
表达式是由运算符、操作数和括号按照一定规则组成的式子,用于计算并返回一个值。
4.1.1 表达式的组成
- 操作数:参与运算的数据,可以是:
- 常量:直接给定的数值,如
3、5.0 - 变量:存储数据的容器,如
a、b、c - 函数调用:返回值的函数(后续章节介绍)
- 常量:直接给定的数值,如
- 运算符:对操作数进行运算的符号,如
+、-、*、/等 - 表达式的值:表达式经过运算后得到的结果
4.1.2 GESP考试常见表达式类型
| 类型 | 示例 | 结果 | 说明 |
|---|---|---|---|
| 算术表达式 | 5 + 3 * 2 |
11 |
先乘后加 |
| 关系表达式 | 5 > 3 && 2 < 4 |
true(1) |
逻辑与 |
| 赋值表达式 | a = b = 5 |
a=5, b=5 |
连续赋值 |
| 条件表达式 | (a>b)?a:b |
较大值 | 三目运算符 |
4.2 算术表达式
算术表达式是由算术运算符连接操作数形成的表达式,用于进行数值计算。
4.2.1 算术运算符
| 运算符 | 名称 | 作用 | 示例 | 结果 |
|---|---|---|---|---|
+ |
加法 | 求两个操作数的和 | 5 + 3 |
8 |
- |
减法 | 求两个操作数的差 | 5 - 3 |
2 |
* |
乘法 | 求两个操作数的积 | 5 * 3 |
15 |
/ |
除法 | 求两个操作数的商 | 5.0 / 3 |
约1.6667 |
% |
取余 | 求两个整数相除的余数 | 5 % 3 |
2 |
++ |
自增 | 操作数的值加1 | a++或++a |
a的值增加1 |
-- |
自减 | 操作数的值减1 | a--或--a |
a的值减少1 |
4.2.2 除法运算注意事项
除法运算需要特别注意整数除法和浮点数除法的区别:
整数除法
当两个操作数都是整数时,结果为整数,小数部分被截断:
int a = 5, b = 3;
int result = a / b; // 结果为1,不是1.6667
浮点数除法
至少有一个操作数为浮点数时,结果为浮点数:
double a = 5.0;
int b = 3;
double result = a / b; // 结果为1.66667
强制类型转换
可以通过类型转换将整数转为浮点数进行除法:
int a = 5, b = 3;
double result = (double)a / b; // 结果为1.66667
4.2.3 取余运算注意事项
-
操作数必须为整数:
int a = 5, b = 3; int remainder = a % b; // 正确:结果为2 double x = 5.5, y = 2.5; // double rem = x % y; // 错误:%运算符不能用于浮点数 -
结果的符号与被除数相同:
int a = 5, b = 3; int r1 = a % b; // 5 % 3 = 2 int c = -5, d = 3; int r2 = c % d; // -5 % 3 = -2 int e = 5, f = -3; int r3 = e % f; // 5 % (-3) = 2 int g = -5, h = -3; int r4 = g % h; // -5 % (-3) = -2
4.2.4 自增自减运算符
自增(++)和自减(--)运算符有前缀和后缀两种形式:
| 表达式 | 等价代码 | 表达式的值 | 变量值变化 |
|---|---|---|---|
a = 5; b = a++; |
b = a; a = a+1; |
5 |
a=6, b=5 |
a = 5; b = ++a; |
a = a+1; b = a; |
6 |
a=6, b=6 |
a = 5; b = a--; |
b = a; a = a-1; |
5 |
a=4, b=5 |
a = 5; b = --a; |
a = a-1; b = a; |
4 |
a=4, b=4 |
示例:
// ❌ 不推荐:复杂表达式中使用自增自减
int a = 5;
int b = a++ + ++a; // 结果依赖编译器,避免使用
// ✅ 推荐:单独使用
int c = 5;
c++; // 或 ++c;
cout << c; // 输出6
4.3 赋值表达式
赋值表达式是由赋值运算符连接操作数形成的表达式,用于将一个值赋给变量。
4.3.1 基本赋值运算符
基本赋值运算符为=,格式:
变量 = 表达式;
**功能:**将右边表达式的值赋给左边的变量,整个表达式的值为赋值后变量的值。
示例:
int a;
a = 5 + 3; // 将8赋给a,表达式的值为8
int b = a; // 将a的值赋给b
int c = (a = 10); // 先将10赋给a,再将a的值赋给c
// c的值为10,a的值也为10
4.3.2 复合赋值运算符
复合赋值运算符是基本赋值运算符与其他运算符的结合:
| 运算符 | 示例 | 等价形式 | 含义 |
|---|---|---|---|
+= |
a += 3 |
a = a + 3 |
加后赋值 |
-= |
a -= 3 |
a = a - 3 |
减后赋值 |
*= |
a *= 3 |
a = a × 3 |
乘后赋值 |
/= |
a /= 3 |
a = a ÷ 3 |
除后赋值 |
%= |
a %= 3 |
a = a % 3 |
取余后赋值 |
示例:
int a = 10;
a += 5; // a = 10 + 5 = 15
a -= 3; // a = 15 - 3 = 12
a *= 2; // a = 12 × 2 = 24
a /= 4; // a = 24 ÷ 4 = 6
a %= 2; // a = 6 % 2 = 0
复合赋值的优点:
- 简洁:代码更紧凑
- 高效:某些情况下编译器可以优化
- 易读:当变量名很长时更方便
4.4 关系表达式
关系表达式是由关系运算符连接操作数形成的表达式,用于比较两个操作数的大小关系,结果为布尔值。
4.4.1 关系运算符
| 运算符 | 名称 | 作用 | 示例 | 结果 |
|---|---|---|---|---|
> |
大于 | 判断左边是否大于右边 | 5 > 3 |
true |
< |
小于 | 判断左边是否小于右边 | 5 < 3 |
false |
>= |
大于等于 | 判断左边是否大于等于右边 | 5 >= 5 |
true |
<= |
小于等于 | 判断左边是否小于等于右边 | 5 <= 3 |
false |
== |
等于 | 判断两个操作数是否相等 | 5 == 3 |
|
!= |
不等于 | 判断两个操作数是否不相等 | 5 != 3 |
true |
C++中的布尔值:
true:真(实际值为1)false:假(实际值为0)
示例:
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 5;
cout << (a > b) << endl; // 输出:1 (true)
cout << (a < b) << endl; // 输出:0 (false)
cout << (a >= 10) << endl; // 输出:1 (true)
cout << (b <= 5) << endl; // 输出:1 (true)
cout << (a == b) << endl; // 输出:0 (false)
cout << (a != b) << endl; // 输出:1 (true)
// 布尔值可以直接用true/false表示
bool is_greater = (a > b); // is_greater的值为true
return 0;
}
4.4.2 注意事项
-
优先级:关系运算符的优先级低于算术运算符,高于赋值运算符
int a = 5, b = 3, c = 2; bool result = a + b > c * 2; // 先算a+b和c*2,再比较 // 等价于:(5+3) > (2×2) → 8 > 4 → true -
区分
==和=:int a = 5, b = 3; bool r1 = (a == b); // 比较:a是否等于b,结果为false int r2 = (a = b); // 赋值:将b的值赋给a,整个表达式的值为3 // 注意:r1是布尔值,r2是整数值 -
浮点数比较:浮点数有精度问题,不要直接用
==比较double a = 0.1 + 0.2; // a可能是0.30000000000000004 double b = 0.3; // b是0.3 // 不推荐 bool wrong = (a == b); // 可能为false // 推荐:比较差值是否小于一个很小的数 double epsilon = 0.000001; bool correct = (abs(a - b) < epsilon); // 正确方法
4.5 逻辑表达式
逻辑表达式是由逻辑运算符连接操作数形成的表达式,用于进行逻辑判断,结果为布尔值。
4.5.1 逻辑运算符
| 运算符 | 名称 | 作用 | 示例 | 结果 |
|---|---|---|---|---|
&& |
逻辑与 | 两边的表达式都为真时,结果为真 | (5>3) && (2<4) |
1/true |
| || | 逻辑或 | 两边的表达式至少有一个为真时,结果为真 | (2>5) && (3<4) |
|
! |
逻辑非 | 对表达式的结果取反 | !(5>3) |
0/false |
示例:
#include <iostream>
using namespace std;
int main() {
int age = 15;
int score = 85;
// 逻辑与:两个条件都满足
bool is_qualified = (age >= 12) && (score >= 60);
cout << "是否合格:" << is_qualified << endl; // 输出:1 (true)
// 逻辑或:至少一个条件满足
bool is_special = (age < 10) || (score >= 90);
cout << "是否特殊:" << is_special << endl; // 输出:0 (false)
// 逻辑非:取反
bool is_not_adult = !(age >= 18);
cout << "是否未成年:" << is_not_adult << endl; // 输出:1 (true)
return 0;
}
4.5.2 短路求值
C++中的逻辑运算符&&和||具有短路求值特性:
- 对于
&&:如果左边的表达式为假,右边的表达式不再求值,结果直接为假 - 对于
||:如果左边的表达式为真,右边的表达式不再求值,结果直接为真
4.6 条件表达式(三目表达式)
条件表达式是一种三目运算符(? :)构成的表达式,用于根据条件选择不同的值。
4.6.1 基本格式
表达式1 ? 表达式2 : 表达式3
4.6.2 运算规则
- 计算表达式1的值
- 如果表达式1的值为真(非0),则整个表达式的值为表达式2的值
- 如果表达式1的值为假(0),则整个表达式的值为表达式3的值
示例:
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 5;
// 求最大值
int max = (a > b) ? a : b;
cout << "最大值:" << max << endl; // 输出:10
// 成绩等级
int score = 85;
char grade = (score >= 90) ? 'A' :
(score >= 80) ? 'B' :
(score >= 70) ? 'C' :
(score >= 60) ? 'D' : 'E';
cout << "成绩等级:" << grade << endl; // 输出:B
return 0;
}
4.6.3 条件表达式的优点
- 简洁:一行代码完成简单的条件判断
- 可以作为表达式使用:可以放在赋值语句的右边
- 类型灵活:表达式2和表达式3可以是不同类型,但需要能隐式转换
注意事项:
// ✅ 可以:类型相同或可转换
int x = (a > b) ? 5 : 10;
double y = (a > b) ? 5.0 : 10;
// ❌ 不建议:类型完全不同
// char* z = (a > b) ? "Yes" : 0; // 不推荐
4.7 逗号表达式
逗号表达式是由逗号连接多个表达式形成的表达式。
4.7.1 基本格式
表达式1, 表达式2, ..., 表达式n
4.7.2 运算规则
- 从左到右依次执行
- 整个表达式的值是最后一个表达式的值
- 优先级最低
示例:
int a = 1, b = 2, c;
c = (a++, b++, a + b); // 执行顺序:a++(a=2), b++(b=3), a+b=5
// 结果:a=2, b=3, c=5
4.7.3 使用建议
- 谨慎使用:逗号表达式可能降低代码可读性
- 适用场景:
- for循环的初始化或更新部分
- 需要依次执行多个操作并获取最后一个操作的值
- 避免过度使用:如果逻辑复杂,最好拆分成多行
4.8 运算符的优先级和结合性
4.8.1 运算符优先级
运算符的优先级决定了表达式中运算的先后顺序,优先级高的运算符先进行运算。
常见运算符的优先级(从高到低):
| 优先级 | 运算符 | 描述 | 结合性 |
|---|---|---|---|
| 1 | () |
括号 | 左到右 |
| 2 | ++ -- ! |
自增、自减、逻辑非 | 右到左 |
| 3 | * / % |
乘法、除法、取余 | 左到右 |
| 4 | + - |
加法、减法 | |
| 5 | < <= > >= |
关系运算符 | |
| 6 | == != |
等于、不等于 | |
| 7 | && |
逻辑与 | |
| 8 | || | 逻辑或 | |
| 9 | ? : |
条件运算符 | 右到左 |
| 10 | = += -= *= /= %= |
赋值运算符 | |
| 11 | , |
逗号运算符 | 左到右 |
4.8.2 结合性
当多个优先级相同的运算符同时出现时,运算顺序由结合性决定:
-
左结合:从左到右运算(大多数运算符)
a + b - c // 先算a+b,再减c a * b / c // 先算a*b,再除以c -
右结合:从右到左运算(赋值运算符、条件运算符)
a = b = c // 先算b=c,再算a=b x ? y : z ? a : b // 先算z?a:b,再算x?y:结果
4.8.3 优先级示例
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 3, c = 2;
// 示例1:算术运算符优先级高于关系运算符
bool r1 = a + b > c * 2; // 等价于:(5+3) > (2×2) → 8 > 4 → true
// 示例2:关系运算符优先级高于逻辑运算符
bool r2 = a > b && b > c; // 等价于:(5>3) && (3>2) → true && true → true
// 示例3:逻辑非优先级高于逻辑与
bool r3 = !a && b; // 等价于:(0) && 3 → false && true → false
// 示例4:赋值运算符优先级最低
int d;
d = a + b * c; // 先算b*c=6,再算a+6=11,最后赋值给d
cout << "r1 = " << r1 << endl; // 1
cout << "r2 = " << r2 << endl; // 1
cout << "r3 = " << r3 << endl; // 0
cout << "d = " << d << endl; // 11
return 0;
}
4.8.4 使用建议
-
使用括号明确优先级:
// 不明确 int result1 = a + b * c; // 明确 int result2 = a + (b * c); // 使用括号明确优先级 int result3 = (a + b) * c; // 如果意图是先加后乘 -
记忆口诀:
- 括号最高
- 算术 > 关系 > 逻辑
- 赋值最低
-
复杂表达式拆分:
// 复杂的表达式 bool complex = (a > b) && (b > c) || (a == 5); // 拆分成多步更清晰 bool cond1 = (a > b) && (b > c); bool cond2 = (a == 5); bool complex = cond1 || cond2;
4.9 常见错误与注意事项
4.9.1 常见错误
-
混淆
=和==:// ❌ 错误 int a = 5; if (a = 10) { // 总是真,因为a=10返回10(非0) cout << "a是10"; } // ✅ 正确 if (a == 10) { // 比较 cout << "a是10"; } -
整数除法问题:
int a = 5, b = 2; double result = a / b; // 错误:结果为2.0,不是2.5 // 正确 double correct_result = (double)a / b; // 2.5 -
自增自减混淆:
int a = 5; int b = a++ + ++a; // 不推荐:结果依赖编译器 // 推荐:拆分成多步 int c = a++; int d = ++a; int e = c + d;
第5章 分支/判断结构
分支语句是程序控制流的重要组成部分,它允许程序根据不同的条件执行不同的代码块。在C/C++语言中,常见的分支语句包括 if 语句和 switch 语句。
5.1 if 语句
if 语句是最基本的分支语句,用于根据条件判断是否执行某段代码。
5.1.1 基本语法
if (条件表达式) {
// 当条件表达式为真时执行的语句块
}
- 条件表达式:可以是关系表达式、逻辑表达式或其他返回布尔值的表达式(在C语言中,非0值表示真,0表示假;在C++中,true 表示真,false 表示假)。
- 语句块:由一对大括号
{}括起来的一条或多条语句。如果语句块中只有一条语句,大括号可以省略,但为了代码的可读性和规范性,建议始终使用大括号。
5.1.2 执行逻辑
首先计算条件表达式的值,如果值为真,则执行语句块中的内容;如果值为假,则跳过语句块,执行 if 语句之后的代码。
示例:
int age = 18;
if (age >= 18) {
cout << "已成年" << endl;
}
上述代码中,条件表达式 age >= 18 的值为真,因此会输出“已成年”。
5.2 if-else 语句
if-else 语句在 if 语句的基础上增加了一个分支,用于在条件为假时执行另一段代码。
5.2.1 基本语法
if (条件表达式) {
// 当条件表达式为真时执行的语句块
} else {
// 当条件表达式为假时执行的语句块
}
5.2.2 执行逻辑
计算条件表达式的值,如果为真,执行 if 后面的语句块;如果为假,执行 else 后面的语句块。两个语句块只会执行其中一个。
示例:
int score = 75;
if (score >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
这里条件表达式 score >= 60 为真,所以输出“及格”。若 score 为 50,条件为假,则输出“不及格”。
5.3 if-else if-else 语句
当需要判断多个条件时,可以使用 if-else if-else 语句,它可以实现多分支选择。
5.3.1 基本语法
if (条件表达式1) {
// 条件表达式1为真时执行的语句块
} else if (条件表达式2) {
// 条件表达式1为假,条件表达式2为真时执行的语句块
} else if (条件表达式3) {
// 前面的条件都为假,条件表达式3为真时执行的语句块
} ... else {
// 所有条件都为假时执行的语句块
}
5.3.2 执行逻辑
程序会依次判断各个条件表达式,当遇到第一个为真的条件表达式时,执行对应的语句块,然后跳过整个 if-else if-else 结构;如果所有条件表达式都为假,则执行 else 后面的语句块(如果有 else 的话)。
示例:
int grade = 85;
if (grade >= 90) {
printf("优秀\n");
} else if (grade >= 80) {
printf("良好\n");
} else if (grade >= 60) {
printf("及格\n");
} else {
printf("不及格\n");
}
上述代码中,grade 为 85,满足 grade >= 80,因此输出“良好”。
5.3.3 注意事项
- 各个条件表达式的判断顺序很重要,应将范围小的条件放在前面,避免条件被覆盖。例如,若将
grade >= 60放在grade >= 80前面,则 85 分会被判断为“及格”,而不是“良好”。 else子句是可选的,如果没有else,当所有条件都为假时,整个结构不执行任何操作。
5.4 switch 语句
switch 语句也用于多分支选择,适用于判断一个变量与多个常量值是否相等的情况。
5.4.1 基本语法
switch (表达式) {
case 常量值1:
// 当表达式的值等于常量值1时执行的语句
break;
case 常量值2:
// 当表达式的值等于常量值2时执行的语句
break;
...
case 常量值n:
// 当表达式的值等于常量值n时执行的语句
break;
default:
// 当表达式的值不等于任何常量值时执行的语句
break;
}
| 规则 | 说明 | 示例 |
|---|---|---|
| 表达式类型 | 必须是整型或字符型 | int, char, 枚举 |
| case常量 | 必须是常量,不能重复 | case 1:, case 'A': |
| break作用 | 跳出switch,防止贯穿 | 通常每个case都要break |
| default | 可选,处理未匹配情况 | 建议总是包含 |
5.4.2 执行逻辑
首先计算表达式的值,然后将该值与各个 case 后面的常量值进行比较。如果找到匹配的常量值,就从该 case 处开始执行语句,直到遇到 break 语句或 switch 语句结束;如果没有找到匹配的常量值,且有 default 子句,则执行 default 后面的语句。
示例:
char grade = 'B';
switch (grade) {
case 'A':
printf("优秀\n");
break;
case 'B':
printf("良好\n");
break;
case 'C':
printf("及格\n");
break;
default:
printf("不及格\n");
break;
}
由于 grade 的值为 'B',所以会执行 case 'B' 后面的语句,输出“良好”,然后遇到 break,跳出 switch 语句。
5.4.3 注意事项
-
switch语句中的表达式和case后面的常量值必须是整数类型。 -
多个
case可以共享同一段执行语句,即省略中间的break,例如:switch (num) { case 1: case 3: case 5: printf("奇数\n"); break; case 2: case 4: case 6: printf("偶数\n"); break; }当
num为 1、3、5 时,都会输出“奇数”;为 2、4、6 时,输出“偶数”。 -
default子句的位置可以灵活放置,不一定在最后,但通常建议放在最后。
5.5 分支语句的嵌套
分支语句可以嵌套使用,即在 if 语句或 switch 语句的语句块中包含其他分支语句。
示例:
int score;
char gender;
cin >> score >> gender;
if (score >= 60) {
if (gender == 'M') {
cout << "男生及格";
} else if (gender == 'F') {
cout << "女生及格";
} else {
cout << "性别输入错误";
}
} else {
cout << "不及格";
}
上述代码中,外层 if 语句判断 a 是否大于 b,若为真,内层 if 语句再判断 a 比 b 大多少,实现了更复杂的条件判断。
嵌套时需注意代码的缩进,以提高可读性,同时要注意各层分支的匹配关系,避免逻辑混乱。
第6章 循环结构
循环语句是程序设计中用于重复执行某段代码的重要结构,它能让程序根据条件多次执行相同或相似的操作,极大地提高代码的效率和灵活性。在C/C++中,常见的循环语句包括 for循环、while循环和 do-while循环。此外,还可以使用 break 和 continue 语句对循环流程进行控制。
6.1 for循环
for循环是一种结构清晰、使用灵活的循环语句,特别适用于已知循环次数的场景。
6.1.1 基本语法
for (初始化表达式; 循环条件表达式; 循环后操作表达式) {
// 循环体:需要重复执行的语句块
}
- 初始化表达式:在循环开始前执行一次,通常用于初始化循环变量。
- 循环条件表达式:每次执行循环体前判断,若为真则执行循环体,否则退出循环。
- 循环后操作表达式:每次循环体执行完后执行,通常用于更新循环变量。
- 循环体:需要重复执行的代码块,建议始终使用大括号
{}。
6.1.2 执行流程
开始
↓
初始化 → 循环条件 → 假 → 结束
↓真
循环体
↓
更新
↓
循环条件
6.1.3 示例
// 输出1到5的整数
for (int i = 1; i <= 5; i++) {
cout << i << " ";
}
// 输出结果:1 2 3 4 5
6.1.4 特殊for循环形式
// 1. 省略初始化(已在前面定义)
int i = 0;
for (; i < 10; i++) { ... }
// 2. 省略更新(在循环体内更新)
for (int i = 0; i < 10;) {
i++; // 在循环体内更新
}
// 3. 无限循环(慎用!)
for (;;) { // 相当于while(true)
// 需要break退出
}
// 4. 多个变量
for (int i=0, j=10; i<j; i++, j--) {
cout << i << " " << j << endl;
}
6.2 while循环
while循环是一种先判断条件再执行循环体的循环语句,适用于循环次数不确定但已知终止条件的场景。
6.2.1 基本语法
while (循环条件表达式) {
// 循环体
}
6.2.2 while vs for 对比
| 特点 | for循环 | while循环 |
|---|---|---|
| 适用场景 | 循环次数已知 | 循环次数未知 |
| 初始化 | 在()内 | 在循环外 |
| 更新 | 在循环体内 | |
| 可读性 | 结构紧凑 | 更灵活 |
6.2.3 示例
int score;
cout << "请输入成绩(0-100): ";
cin >> score;
while (score < 0 || score > 100) {
cout << "输入错误,请重新输入: ";
cin >> score;
}
cout << "输入正确: " << score;
6.2.4 注意事项
- 必须在循环体内包含改变循环条件的语句,否则可能导致无限循环。
- 初始化操作需在循环外完成,变量更新在循环体内实现。
6.3 do-while循环
do-while循环是一种先执行循环体再判断条件的循环语句,保证循环体至少执行一次,适用于需要先执行一次再判断是否继续的场景。
6.3.1 基本语法
do {
// 循环体
} while (循环条件表达式);
注意:表达式末尾的分号不可省略。
6.3.2 执行流程
- 执行循环体。
- 判断循环条件表达式:
- 若为真,返回步骤1;
- 若为假,退出循环。
6.3.3 示例
// 输入一个正整数,直到输入正确为止
int num;
do {
printf("请输入一个正整数:");
scanf("%d", &num);
} while (num <= 0);
printf("你输入的正整数是:%d\n", num);
6.3.4 与while的区别
// while:先判断,后执行(可能一次都不执行)
int i = 10;
while (i < 5) { // 条件为假
cout << i; // 不执行
}
// do-while:先执行,后判断(至少执行一次)
int j = 10;
do {
cout << j; // 执行一次,输出10
} while (j < 5); // 然后判断条件为假,退出
6.4 循环控制语句
循环控制语句用于在循环过程中改变循环的执行流程,包括 break 和 continue。
6.4.1 break语句
用于立即终止当前循环,跳出循环体,执行循环后面的代码。
// 寻找1到10中第一个能被3整除的数
for (int i = 1; i <= 10; i++) {
if (i % 3 == 0) {
cout << "找到的数是:" << i << endl;
break; // 找到后立即退出循环
}
}
// 输出:找到的数是:3
6.4.2 continue语句
用于跳过本次循环中剩余的语句,直接进入下一次循环的判断。
// 输出1到10中的奇数
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数
}
printf("%d ", i);
}
// 输出结果:1 3 5 7 9
6.4.3 break与continue的区别
- break:完全终止循环,不再进行后续的循环判断和执行。
- continue:仅跳过当前循环的剩余部分,继续下一次循环的判断和执行。
6.4.4 break vs continue 对比
| 操作 | 作用 | 示例 |
|---|---|---|
| break | 完全退出循环 | 找到目标后停止搜索 |
| continue | 跳过本次循环 | 跳过不符合条件的数据 |
6.5 循环嵌套
6.5.1 嵌套循环执行原理
for (int i = 1; i <= 3; i++) { // 外层循环
for (int j = 1; j <= 2; j++) { // 内层循环
cout << "i=" << i << ", j=" << j << endl;
}
}
输出结果:
i=1, j=1
i=1, j=2
i=2, j=1
i=2, j=2
i=3, j=1
i=3, j=2
执行次数:外层3次 × 内层2次 = 6次
6.5.2 典型应用:乘法表
// 打印九九乘法表
for (int i = 1; i <= 9; i++) { // 行
for (int j = 1; j <= i; j++) { // 列,j<=i打印下三角
cout << j << "×" << i << "=" << i*j << "\t";
}
cout << endl; // 换行
}
6.5.3 控制嵌套循环
// break只退出当前层循环
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i * j > 4) {
break; // 只退出内层循环
}
cout << i*j << " ";
}
cout << endl;
}
6.6 循环算法题训练
6.6.1 求和问题
// 1. 求1+2+3+...+n的和
int n, sum = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
sum += i;
}
cout << "和为: " << sum << endl;
// 2. 求1-100中偶数的和
int evenSum = 0;
for (int i = 2; i <= 100; i += 2) {
evenSum += i;
}
cout << "偶数和: " << evenSum << endl;
6.6.2 计数问题
// 统计1-100中能被3整除的数的个数
int count = 0;
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0) {
count++;
}
}
cout << "个数: " << count << endl;
6.6.3 找最值问题
// 输入n个数,找最大值
int n, maxNum;
cin >> n >> maxNum; // 先读n,再读第一个数作为初始最大值
for (int i = 1; i < n; i++) {
int num;
cin >> num;
if (num > maxNum) {
maxNum = num;
}
}
cout << "最大值: " << maxNum << endl;
6.6.4 图形打印
// 打印直角三角形
int rows;
cin >> rows;
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= i; j++) {
cout << "*";
}
cout << endl;
}
// 打印倒三角形
for (int i = rows; i >= 1; i--) {
for (int j = 1; j <= i; j++) {
cout << "*";
}
cout << endl;
}