1. 计算机系统概述

1.1 冯·诺依曼体系结构

现代计算机大多基于冯·诺依曼体系结构,其核心思想包括:

  1. 采用二进制表示数据和指令
  2. 程序和数据存储在存储器中,可被自动执行
  3. 计算机由五大基本部件组成:
    • 运算器
    • 控制器
    • 存储器
    • 输入设备
    • 输出设备

重点:这是现代计算机的基本设计蓝图,理解它有助于掌握计算机的工作原理。

2. 计算机硬件组成

2.1 CPU(中央处理器)

CPU是计算机的“大脑”,负责执行指令和处理数据。

2.1.1 CPU的组成

  • 运算器:执行算术运算(加减乘除)和逻辑运算(与或非)
  • 控制器:协调控制各部件工作(取指令、分析指令、执行指令)
  • 寄存器:高速存储部件,临时存放CPU正在处理的数据和指令

2.1.2 CPU性能指标

指标 说明 影响
主频 CPU时钟频率(Hz) 频率越高,单位时间执行指令越多
核心数 CPU中独立运算核心数量 核心越多,多任务处理能力越强
字长 CPU一次能处理的二进制位数 字长越长,处理能力越强(32位/64位)

2.2 存储器层次结构

2.2.1 Cache(高速缓冲存储器)

  • 位置:CPU与内存之间
  • 作用:临时存储CPU频繁访问的数据和指令
  • 特点:速度极快,容量小(L1<L2<L3)
  • 工作方式
    • 命中:数据在Cache中找到,直接读取
    • 未命中:数据不在Cache中,从内存读取并加载到Cache

2.2.2 内存(主存储器)

  • 特点
    • 直接与CPU交换数据
    • 存取速度快
    • 容量相对较小
    • 断电后数据丢失
  • 分类
    • RAM(随机存取存储器)
      • DRAM:速度较慢,成本低(主流内存)
      • SRAM:速度快,成本高
    • ROM(只读存储器):存储BIOS等固件,断电不丢失

2.2.3 外存(辅助存储器)

  • 特点
    • 容量大
    • 断电后数据不丢失
    • 速度慢,不能直接与CPU交换数据
  • 常见类型
    • 硬盘(HDD):容量大、成本低、速度慢
    • 固态硬盘(SSD):速度快、抗震、成本高
    • 光盘:CD、DVD等
    • U盘:便携移动存储

2.3 总线系统

总线是计算机各部件之间传输信息的公共通信干线。

总线类型 功能 特点
数据总线 传输数据信息 位数与CPU字长对应
地址总线 传输存储器地址信息 位数决定可访问的最大内存容量
控制总线 传输控制信号和时序信号 协调各部件工作

总线特点:共享性(同一时间只能一个设备发送,多个设备接收)

2.4 输入/输出设备

类型 设备示例 功能
输入设备 键盘、鼠标、扫描仪、摄像头、麦克风 向计算机输入数据和指令
输出设备 显示器、打印机、音箱、投影仪 将处理结果输出给人

3. 计算机软件系统

3.1 系统软件

管理、控制和维护计算机硬件和软件资源,为应用软件提供运行环境。

3.1.1 操作系统(OS)

  • 功能:管理硬件和软件资源,控制程序执行,提供人机界面
  • 示例:Windows、macOS、Linux、Android、iOS

3.1.2 语言处理程序

类型 工作方式 示例
编译器 整个源程序一次性翻译成目标程序 C/C++编译器
解释器 逐行解释执行源程序 Python解释器
汇编程序 将汇编语言转换为机器语言 汇编器

3.1.3 数据库管理系统(DBMS)

  • 功能:管理数据库的建立、维护、查询、更新
  • 示例:MySQL、Oracle、SQL Server

3.1.4 实用程序

  • 功能:辅助计算机日常维护和管理
  • 示例:杀毒软件、磁盘清理工具、备份软件

3.2 应用软件

为解决特定领域问题或满足特定需求而开发的软件。

类别 功能 示例
办公软件 日常办公处理 Word、Excel、PowerPoint
图形图像软件 图形设计、图像处理 Photoshop、Illustrator
多媒体软件 音频视频处理 Premiere、Audition
行业专用软件 特定行业应用 医疗管理系统、证券交易软件

4. 计算机网络基础

4.1 网络体系结构

4.1.1 OSI七层模型

层次 功能 示例/协议
物理层 传输原始比特流 网线、光纤、网卡
数据链路层 封装成帧,相邻节点可靠传输 以太网协议
网络层 源到目标主机数据传输,路由选择 IP协议
传输层 端到端可靠数据传输 TCPUDP
会话层 建立、维护、终止会话连接 -
表示层 数据编码、格式转换、加密解密
应用层 为用户应用程序提供网络服务 HTTP、FTP、SMTP

4.1.2 TCP/IP四层模型

层次 对应OSI层 主要协议
网络接口层 物理层+数据链路层 以太网协议
网络层 网络层 IP协议
传输层 传输层 TCPUDP
应用层 会话层+表示层+应用层 HTTP、FTP、DNS

重点:TCP/IP是实际使用的模型,需重点掌握各层功能。

4.2 IP地址

4.2.1 IPv4地址

  • 格式:32位二进制,点分十进制表示(如192.168.1.1
  • 每段范围:0-255

4.2.2 IPv4地址分类

类别 首字节范围 默认子网掩码 用途
A类 1-126 255.0.0.0 大型网络
B类 128-191 255.255.0.0 中型网络
C类 192-223 255.255.255.0 小型网络
D类 224-239 - 多播通信
E类 240-255 实验研究

4.2.3 子网掩码

  • 作用:区分IP地址中的网络部分和主机部分
  • 示例192.168.1.100 + 255.255.255.0
    • 网络部分:192.168.1
    • 主机部分:100

4.2.4 IPv6地址

  • 背景:IPv4地址资源枯竭
  • 格式:128位二进制,8组4位十六进制数(如2001:0db8:85a3::8a2e:0370:7334

4.3 域名系统(DNS)

4.3.1 域名结构

  • 格式www.example.com
    • .com顶级域名(商业机构)
    • example二级域名(机构名称)
    • www三级域名(服务器名)
  • 常见顶级域名
    • .com商业机构 | .org非营利组织 | .edu教育机构
    • .gov政府机构 | .cn中国国家域名

4.3.2 DNS查询过程

  1. 检查本地DNS缓存 → 2. 查询本地DNS服务器 → 3. 查询根域名服务器
  2. 查询顶级域名服务器 → 5. 查询权威域名服务器 → 6. 返回IP地址并缓存

4.4 HTML基础(了解即可)

4.4.1 HTML文档结构

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>网页标题</title>
</head>
<body>
    <h1>一级标题</h1>
    <p>段落内容</p>
</body>
</html>

4.4.2 常用HTML标签

标签 功能 示例
<h1>-<h6> 标题标签 <h1>一级标题</h1>
<p> 段落标签 <p>这是一个段落</p>
<a> 超链接 <a href="...">链接</a>
<img> 图像 <img src="..." alt="...">
<ul>/<ol> 无序/有序列表 <li>列表项
<div>/<span> 分区/行内分组 布局和样式

4.4.3 Web开发三要素

技术 作用 特点
HTML 网页结构 定义元素(标题、段落等)
CSS 网页样式 设置颜色、字体、布局
JavaScript 网页交互 表单验证、动态内容

5. 计算机语言概述

5.1 计算机语言发展历史

5.1.1 机器语言

  • 形式:二进制代码(0和1)
  • 特点
    • 执行效率极高
    • 依赖具体硬件,不可移植
    • 可读性极差,难编写调试
  • 现状:几乎不直接使用

5.1.2 汇编语言

  • 形式:助记符(如ADD、MOV)
  • 特点
    • 可读性有所提高
    • 仍依赖硬件,可移植性差
    • 需汇编程序翻译成机器语言
  • 应用:系统底层开发、嵌入式编程

5.1.3 高级语言发展

时期 特点 代表语言
早期(1950-60s) 接近自然语言,可移植性提升 FORTRAN、COBOL、ALGOL
结构化(1970-80s) 结构化程序设计,代码模块化 Pascal、C语言、BASIC
面向对象(1980s-今) 以对象为核心,代码复用性强 C++JavaPython
现代脚本与专用(21世纪) 解释型为主,针对特定领域 JavaScript、PHP、Go、Rust

5.2 计算机语言分类

5.2.1 按抽象层次划分

类型 特点 优点 缺点 代表语言
低级语言 直接与硬件交互 执行效率高,直接操作硬件 开发效率低,可移植性差 机器语言、汇编语言
高级语言 接近自然语言和数学逻辑 开发效率高,可读性好,可移植性强 执行效率通常较低 C、C++、Python

5.2.2 按执行方式划分

类型 工作方式 特点 代表语言
编译型 源代码→编译→可执行文件 执行速度快,可独立运行,修改需重新编译 CC++、Go、Rust
解释型 解释器逐行解释执行 开发调试便捷,跨平台好,执行速度慢 Python、JavaScript、PHP
混合型 源代码→中间代码→虚拟机解释 兼顾跨平台和效率 Java、C#

重点:C++是编译型语言,需要理解编译、链接的过程。

5.2.3 按编程范式划分

范式 核心思想 特点 代表语言
结构化 函数/过程为单位,顺序/分支/循环 代码模块化,避免goto,适合中小程序 C、Pascal、BASIC
面向对象 对象为核心,封装/继承/多态 代码复用性强,适合大型程序 C++Java、Python
函数式 函数为核心,无副作用 适合并行计算,代码简洁 Lisp、Haskell
脚本语言 语法简洁,解释执行 开发效率高,依赖宿主环境 Python、JavaScript

5.2.4 按应用领域划分

类型 应用领域 代表语言
通用编程语言 多种领域开发 CC++、Java、Python
专用编程语言 特定领域优化 SQL(数据库)、MATLAB(科学计算)

5.3 各类语言特点总结

语言类型 代表语言 核心特点 典型应用场景
机器语言 二进制指令 直接执行,效率极高;可读性极差 早期计算机,现几乎不用
汇编语言 x86/ARM汇编 接近硬件;可移植性差 系统底层、嵌入式
编译型高级语言 CC++ 编译后执行,速度快;可移植性较好 操作系统、游戏、嵌入式
解释型高级语言 Python、JavaScript 解释执行,开发便捷;执行较慢 Web开发、脚本、数据分析
混合型语言 Java、C# 编译为中间代码,虚拟机执行 企业级应用、移动应用
面向对象语言 C++、Java、Python 封装、继承、多态;适合大型程序 大型软件系统
函数式语言 Haskell、Lisp 无副作用函数,强调数学逻辑 人工智能、科学计算
专用语言 SQL、MATLAB 针对特定领域优化;通用性差 数据库、科学计算

5.4 计算机语言发展趋势

  1. 更高的开发效率:语法简洁,抽象层次高(Python、Go)
  2. 更强的跨平台性:虚拟机、容器技术(Java的“一次编写,到处运行”)
  3. 更好的安全性:注重内存安全、类型安全(Rust的所有权机制)
  4. 适应新兴领域:AI、大数据、云计算专用语言和库
  5. 多范式融合:单一范式→多范式发展(C++、Python支持多种范式)

6. 流程图与算法描述

6.1 流程图的基本概念

6.1.1 定义与作用

流程图是一种用标准化图形符号、箭头和文字说明来表示算法或程序执行步骤的可视化工具。

核心作用

作用 说明 对GESP的意义
可视化逻辑 将抽象算法转化为直观图形,便于理解和沟通 帮助初学者理解程序执行流程
梳理流程 编程前规划程序结构,避免逻辑漏洞 培养编程前的设计习惯
调试辅助 通过流程图定位逻辑错误 提升代码调试能力
标准化表达 统一符号,便于交流 标准化表示算法思想

重点:流程图是算法的图形化表示,是编写程序前的重要设计步骤。

6.1.2 流程图的分类

类型 描述 适用场景
程序流程图 描述程序执行步骤,包括顺序、分支、循环等结构 GESP二级主要考察类型
系统流程图 描述整个系统的模块划分和数据流向 大型程序设计
业务流程图 描述实际业务处理流程 系统分析与设计

6.2 流程图的基本符号

6.2.1 常用符号及含义

符号形状 名称 含义与应用场景 示例
![圆角矩形] 开始/结束框 表示流程的起点(标注"开始")或终点(标注"结束") 开始结束
![矩形] 处理框 表示具体的操作或处理步骤 sum = a + b
![菱形] 判断框 表示分支判断,有两个或多个出口 x > 0 ?
![平行四边形] 输入/输出框 表示数据的输入或输出操作 输入n输出result
![箭头] 流向线 表示流程的执行方向 连接各个符号

注意:判断框的出口必须标注逻辑方向(如"是"/"否"或"Y"/"N")

6.2.2 符号使用原则

  1. 大小适中:符号大小要合适,便于阅读
  2. 文字简洁:框内用简洁明了的文字(如用i++代替"将变量i的值增加1")
  3. 方向规范:流向线尽量从上到下、从左到右绘制
  4. 避免交叉:流向线尽量避免交叉,必要时用连接点

6.3 流程图的基本结构

6.3.1 顺序结构

定义

步骤按先后顺序依次执行,无分支或循环

图示特点

各符号用流向线依次连接,形成一条直线。

示例:计算两数之和

graph TD  
A[开始] --> B[输入整数a]  
B --> C[输入整数b]  
C --> D[sum = a + b]  
D --> E[输出sum]  
E --> F[结束]
// 顺序结构示例
#include <iostream>
using namespace std;

int main() {
    int a, b, sum;
    cin >> a;           // 输入a
    cin >> b;           // 输入b
    sum = a + b;        // 计算和
    cout << sum << endl; // 输出结果
    return 0;
}

6.3.2 分支结构(选择结构)

定义

根据判断条件的真假,选择执行不同的分支。

分类

类型 描述 适用场景
双分支 满足条件执行分支A,否则执行分支B 最常用
多分支 根据多个条件判断,选择多个分支中的一个 多个条件的情况

示例1:双分支(判断正数)

graph TD
    A[开始] --> B[输入整数x]
    B --> C{x > 0?}
    C -->|是| D[输出&quot;Positive&quot;]
    C -->|否| E[输出&quot;Non-positive&quot;]
    D --> F[结束]
    E --> F
// 双分支结构示例
#include <iostream>
using namespace std;

int main() {
    int x;
    cin >> x;
    
    if (x > 0) {
        cout << "Positive" << endl;
    } else {
        cout << "Non-positive" << endl;
    }
    
    return 0;
}

示例2:多分支(成绩等级)

graph TD
    A[开始] --> B[输入成绩score]
    B --> C{score >= 90?}
    C -->|是| D[输出&quot;A&quot;]
    C -->|否| E{score >= 80?}
    E -->|是| F[输出&quot;B&quot;]
    E -->|否| G{score >= 60?}
    G -->|是| H[输出&quot;C&quot;]
    G -->|否| I[输出&quot;D&quot;]
    D --> J[结束]
    F --> J
    H --> J
    I --> J
// 多分支结构示例
#include <iostream>
using namespace std;

int main() {
    int score;
    cin >> score;
    
    if (score >= 90) {
        cout << "A" << endl;
    } else if (score >= 80) {
        cout << "B" << endl;
    } else if (score >= 60) {
        cout << "C" << endl;
    } else {
        cout << "D" << endl;
    }
    
    return 0;
}

重点:分支结构最终必须汇合到同一出口,避免流程发散。\

6.3.3 循环结构

定义

根据条件重复执行某段流程(循环体)。

分类

类型 描述 特点 C++对应语句
当型循环 先判断条件,为真则执行循环体 可能一次都不执行 while
直到型循环 先执行循环体,再判断条件 至少执行一次 do-while

类型1:当型循环(While型)

流程图示例(打印1-5):

graph TD
    A[开始] --> B[i = 1]
    B --> C{i < 5?}
    C -->|是| D[输出i]
    D --> E[i++]
    E --> C
    C -->|否| F[结束]

6.4 流程图的绘制规则与技巧

6.4.1 绘制规则

规则 说明 示例
标准化符号 严格使用规定符号(判断必须用菱形) 不能矩形替代菱形
单一入口出口 整个流程图有唯一的开始框,分支/循环最终汇合 避免多个独立出口
逻辑清晰 步骤顺序合理,避免不必要的跳转 避免从循环内直接跳到外部
文字简洁 框内用动词或短句 i++而不是"将i加1"

6.4.2 绘制技巧

技巧 说明 目的
先抽象后细化 先用粗线条勾勒主要步骤,再逐步细化 避免一开始陷入细节
避免交叉线 调整符号位置或使用连接点 提高可读性
嵌套结构缩进 循环体内的分支向右缩进 清晰区分层次
标注层次编号 多层嵌套时标注"循环1"、"分支2" 便于理解复杂结构

6.5 流程图与代码的对应关系

6.5.1 顺序结构

流程图:A → B → C C++代码

A;  // 步骤A
B;  // 步骤B
C;  // 步骤C

6.5.2 分支结构

双分支

流程图:判断条件→是→A;否→B→汇合 C++代码

if (条件) {
    A;  // 条件成立执行的代码
} else {
    B;  // 条件不成立执行的代码
}

多分支

流程图:条件1→是→A;否→条件2→是→B;否→C C++代码

if (条件1) {
    A;
} else if (条件2) {
    B;
} else {
    C;
}

6.5.3 循环结构

当型循环

流程图:初始化→判断条件→是→循环体→回到判断;否→退出 C++代码

初始化;
while (条件) {
    循环体;
}

直到型循环

流程图:初始化→循环体→判断条件→否→回到循环体;是→退出 C++代码

初始化;
do {
    循环体;
} while (条件);  // 注意:条件为假时继续循环

第7章 ASCII编码

7.1 ASCII编码的基本概念

7.1.1 定义与作用

  • 定义:ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是一套基于拉丁字母的字符编码系统,通过7位二进制数(共128种组合)表示大小写字母、数字、标点符号及控制字符。
  • 作用:统一字符与二进制数值的对应关系,使计算机能够存储、传输和处理文本信息(如键盘输入、屏幕显示、文件读写等)。

7.1.2 编码规则

  • 位数:基础ASCII编码使用7位二进制数(0000000 ~ 1111111),对应十进制范围0~127,共128个字符。
  • 存储形式:在计算机中,ASCII字符通常用1个字节(8位)存储,最高位(第8位)为0(用于兼容扩展编码)。
  • 对应关系:每个字符唯一对应一个十进制数值(如字符A对应65,字符0对应48)。

7.2 ASCII字符的分类

根据功能和数值范围,ASCII字符可分为以下几类:

7.2.1 控制字符(十进制0~31,127)

  • 定义不可打印的字符,用于控制设备(如打印机、终端)的操作,无实际显示符号。
  • 常用控制字符
    • 0 (NULL, 空字符):表示字符串结束(C/C++中'\0')。(重点)
    • 10 (LF,换行):将光标移至下一行开头('\n')。
    • 13 (CR,回车):将光标移至当前行开头('\r')。
    • 27 (ESC):退出或取消操作。
    • 127 (DEL,删除):删除光标前的字符。

7.2.2 可打印字符(十进制32~126)

  1. 空格字符 (32) 十进制值32,对应字符 ' '(空格),用于分隔文本中的单词或字符。
  2. 数字字符 (48~57)
    • 十进制值48对应‘0’49对应‘1’,...,57对应‘9’
    • 编码值连续:相邻数字的编码值连续递增(如'5' - '0' = 5)。
  3. 大写字母 (65~90) (重点)
    • 十进制值65对应‘A’66对应‘B’,...,90对应‘Z’
    • 编码值连续:相邻字母编码值连续(如'C' - 'A' = 2)。
  4. 小写字母 (97~122) (重点)
    • 十进制值97对应‘a’98对应‘b’,...,122对应‘z’
    • 编码值连续:相邻字母编码值连续(如'd' - 'a' = 3)。
    • 大小写字母转换小写字母编码值 = 大写字母编码值 + 32(如‘a’ = ‘A’ + 32)。
  5. 标点符号与特殊字符(其余可打印字符)
    • 包括运算符(+, -, *, /)、标点(!, ?, ;)、括号((, ), {, })等。
    • 部分常用字符的编码值:33: '!', 43: '+', 45: '-', 61: '=', 63: '?', 95: '_'

7.3 常用 ASCII 编码值速查表

字符 十进制值 二进制值 分类
\0 0 00000000 控制字符(空字符)
`` (空格) 32 00100000 可打印字符
0 48 00110000 数字
9 57 00111001
A 65 01000001 大写字母
Z 90 01011010
a 97 01100001 小写字母
z 122 01111010
\n 10 00001010 控制字符(换行)
\r 13 00001101 控制字符(回车)

7.4 扩展 ASCII 编码

7.4.1 定义与编码规则

  • 扩展ASCII编码(Extended ASCII)是对基础ASCII的扩展,使用8位二进制数(00000000 ~ 11111111)表示字符,共包含256个字符(十进制值0~255)。
  • 其中0~127与基础ASCII完全一致128~255为扩展字符集,用于补充基础ASCII未涵盖的符号。

7.4.2 扩展字符的分类(128~255)

  • 拉丁扩展字符:带重音(accents)的欧洲语言字符,如 à (133)、é (130)、ñ (164)等。
  • 图形符号:线条符号(如— (196))、块状符号(如■ (254)、● (183))。
  • 特殊符号:货币符号(如€ (128)、£ (163)、¥ (165))、数学符号(如± (177)、× (215)、÷ (247))。

7.4.3 扩展ASCII的局限性 (重点)

  • 无统一标准:不同系统(如Windows、DOS、Linux)采用的扩展ASCII表存在差异(如十进制128在Windows中表示,在其他系统中可能表示其他符号)。
  • 跨平台兼容性差:由于标准不统一,使用扩展ASCII字符的程序在不同系统中可能显示异常,因此建议优先选择基础ASCII字符

7.4.4 扩展ASCII编码值示例(Windows-1252标准)

十进制值 字符 描述
128 欧元符号
169 © 版权符号
174 ® 注册商标符号
192 À 带重音的大写A
215 × 乘号
247 ÷ 除号
254 实心方块

7.5 ASCII编码在C/C++中的应用

7.5.1 字符与整数的转换

在C/C++中,char类型本质是8位整数,可直接与int类型相互转换(利用ASCII编码值)。(重点)

char c = 'A';
int num = c; // num = 65 ('A'的ASCII值)
char d = 97; // d = 'a' (97对应小写字母a)

7.5.2 字符判断与处理

  • 判断字符类型

    // 判断是否为大写字母
    bool isUpper(char c) {
        return c >= 'A' && c <= 'Z'; // 利用ASCII值范围
    }
    // 判断是否为数字字符
    bool isDigit(char c) {
        return c >= '0' && c <= '9';
    }
    
  • 字符转换

    // 大写字母转小写字母
    char toLower(char c) {
        if (c >= 'A' && c <= 'Z') { // 先判断是否为大写
            return c + 32; // 利用大小写字母 ASCII 值差 32 (重点)
        }
        return c;
    }
    // 类似地,小写转大写可用 c - 32
    

7.5.3 字符串处理 (重点)

  • 字符串以'\0'(ASCII值0)为结束标志,用于判断字符串长度或终止遍历。

    // 计算字符串长度(不包含'\0')
    int strLength(const char* str) {
        int len = 0;
        while (str[len] != '\0') { // 当字符为'\0'时结束
            len++;
        }
        return len;
    }
    

7.5.4 输入输出操作

  • printf/cout 输出字符时,会自动根据ASCII值显示对应符号;输入时,键盘字符会被转换为ASCII值存储。

    char c;
    cin >> c; // 输入'A', c 存储 65
    cout << c; // 输出'A'(65 对应的字符)
    printf("%d", c); // 输出 65(直接打印 ASCII 值)
    

7.6 ASCII 的局限与替代编码

7.6.1 局限

  • 仅支持拉丁字母,无法表示中文、日文等非拉丁字符
  • 字符集规模小(基础ASCII仅128个字符),无法满足多语言文本处理需求。
  • 扩展ASCII无统一标准,跨平台兼容性差。

7.6.2 常见替代编码

  • Unicode:包含全球所有语言的字符,采用16位或32位编码,兼容ASCII(0~127完全一致)。在C++中可通过wchar_tchar16_tchar32_t等类型处理。
  • GBK/GB2312:中文编码标准,兼容ASCII,可表示简体中文、繁体中文、日文、韩文等字符。

第8章 循环与分支的嵌套

8.1 嵌套结构概述

在程序设计中,单一的分支或循环语句往往难以满足复杂问题的求解需求。通过将分支语句与循环语句进行嵌套组合,可以构建出更灵活、功能更强大的程序结构,用于处理多层条件判断或重复执行特定操作的场景。

8.2 分支嵌套

8.2.1 if语句的嵌套

if语句的嵌套是指在if、else if或else子句的语句块中包含其他if语句,用于处理存在多层条件判断的场景。

  • 基本语法
if(条件表达式1) {
    // 语句块1
    if(条件表达式2) {
        // 语句块2(条件1为真且条件2为真时执行)
    } else {
        // 语句块3(条件1为真且条件2为假时执行)
    }
} else {
    // 语句块4(条件1为假时执行)
}
  • 执行逻辑
    • 外层if语句先判断条件表达式1
    • 若为真,进入语句块1,此时会执行内层if语句的判断
    • 若条件表达式1为假,则执行else子句的语句块4,内层if语句不执行
  • 示例:成绩等级判断
int score = 85;
if (score >= 60) {
    cout << "及格" << endl;
    if (score >= 90) {
        cout << "优秀" << endl;
    } else if (score >= 80) {
        cout << "良好" << endl;
    } else {
        cout << "中等" << endl;
    }
} else {
    cout << "不及格" << endl;
}
// 输出结果:及格 良好
  • 注意事项
    1. 内层if语句必须完全包含在外层分支的语句块中,通过缩进增强代码可读性
    2. else子句总是与离它最近的未配对的if语句配对,必要时可通过大括号明确嵌套关系,避免逻辑混淆

8.2.2 switch语句的嵌套

switch语句的嵌套是指在某个case或default子句的语句块中包含另一个switch语句。

  • 基本语法
switch (表达式1) {
    case 常量1:
        // 语句块1
        switch (表达式2) {
            case 常量A:
                // 语句块A(表达式1为常量1且表达式2为常量A时执行)
                break;
            default:
                // 语句块B(表达式1为常量1且表达式2不匹配任何常量时执行)
        }
        break;
    default:
        // 语句块2(表达式1不匹配任何常量时执行)
}
  • 示例
int a = 1, b = 2;
switch (a) {
    case 1:
        printf("a=1\n");
        switch (b) {
            case 1:
                printf("b=1\n");
                break;
            case 2:
                printf("b=2\n");
                break;
        }
        break;
    case 2:
        printf("a=2\n");
        break;
}
// 输出结果:a=1 b=2
  • 注意事项
    • 内层switch语句中的break仅作用于内层switch,不会跳出外层switch
    • 嵌套层次不宜过多,否则会降低代码可读性

8.3 循环嵌套

8.3.1 基本概念

循环嵌套指的是在一个循环语句(for、while、do-while)的循环体中包含另一个完整的循环语句。外层循环控制内层循环的执行次数,内层循环则完成具体的重复操作。

8.3.2 for循环的嵌套

for循环的嵌套是最常用的循环嵌套形式,适合处理具有明确边界的多层重复问题(如二维数组遍历)。

  • 基本语法
for (初始化表达式1; 循环条件1; 循环后操作1) {
    // 外层循环体
    for (初始化表达式2; 循环条件2; 循环后操作2) {
        // 内层循环体(外层循环执行一次,内层循环执行一轮)
    }
}
  • 执行逻辑
    • 外层循环每执行一次,内层循环会完整执行所有次数(直到内层循环条件为假)
    • 外层循环变量更新,重复上述过程,直到外层循环条件为假
  • 示例:打印5行5列的矩形星号图案
for (int i = 1; i <= 5; i++) { // 外层循环控制行数
    for (int j = 1; j <= 5; j++) { // 内层循环控制每行星号数
        cout << "* ";
    }
    cout << endl;
}
// 输出结果:
// * * * * *
// * * * * *
// * * * * *
// * * * * *
// * * * * *

8.3.3 while循环的嵌套

while循环的嵌套适用于循环次数不确定,但存在多层重复逻辑的场景。

  • 基本语法
初始化外层循环变量;
while (循环条件1) {
    // 外层循环体
    初始化内层循环变量;
    while (循环条件2) {
        // 内层循环体
        更新内层循环变量;
    }
    更新外层循环变量;
}
  • 示例:计算1-3的每个数的1-2次方之和
int i = 1;
while (i <= 3) {
    int sum = 0;
    int j = 1;
    while (j <= 2) {
        sum += i * j;
        j++;
    }
    printf("%d的1-2次方之和: %d\n", i, sum);
    i++;
}
// 输出结果:
// 1的1-2次方之和: 3
// 2的1-2次方之和: 6
// 3的1-2次方之和: 9

8.3.4 不同类型循环的嵌套

for循环、while循环和do-while循环可以相互嵌套,根据实际需求选择合适的组合。

  • 示例:用for循环嵌套do-while循环打印三角形
for (int i = 1; i <= 3; i++) {
    int j = 1;
    do {
        cout << "* ";
        j++;
    } while (j <= i);
    cout << endl;
}
// 输出结果:
// *
// * *
// * * *

8.3.5 循环嵌套注意事项

  1. 内层循环和外层循环的循环变量应使用不同的变量名(如i和j),避免变量冲突
  2. 嵌套层数越多,程序执行效率可能越低,应尽量优化逻辑,减少不必要的嵌套
  3. 确保内层循环有明确的终止条件,避免出现无限循环

8.4 分支和循环的嵌套

分支和循环的嵌套是指在循环语句中包含分支语句,或在分支语句中包含循环语句,用于处理需要根据条件重复执行不同操作,或在特定条件下执行循环的场景。

8.4.1 循环中嵌套分支

在循环体内部包含分支语句,根据循环过程中的条件动态执行不同的操作。

  • 基本语法(循环中嵌套if):
循环语句{
    if(条件表达式){
        // 满足条件时执行的操作
    } else {
        // 不满足条件时执行的操作
    }
}
  • 示例:计算1-10中偶数的和
int sum = 0;
for (int i = 1; i <= 10; i++) {
    if(i % 2 == 0){
        sum += i;
    }
}
cout << "1-10中偶数的和:" << sum << endl; // 输出结果:30

8.4.2 分支中嵌套循环

在分支语句的语句块中包含循环语句,仅当满足特定条件时才执行循环操作。

  • 基本语法(if中嵌套循环):
if(条件表达式){
    循环语句{
        // 循环执行的操作
    }
} else {
    // 不满足条件时的操作
}
  • 示例:若输入的数大于0,则打印该数的乘法表
int n;
printf("请输入一个整数:");
scanf("%d", &n);
if(n > 0) {
    for(int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d×%d=%d ", j, i, j*i);
        }
        printf("\n");
    }
} else {
    printf("输入的数不大于0,不打印乘法表\n");
}

8.5 嵌套结构的通用注意事项

  1. 结构层次清晰:分支与循环的嵌套应遵循"内层结构完全包含于外层结构"的原则,通过缩进清晰展示层次关系
  2. 控制语句的使用
    • break语句仅跳出当前所在的循环或switch语句,不会跳出外层循环或分支
    • continue语句仅跳过当前循环的剩余部分,不影响分支语句的执行
  3. 可读性与维护性
    • 复杂嵌套结构容易导致逻辑错误,编写时应逐步测试,确保每一层的逻辑正确性
    • 嵌套层次不宜过深,建议不超过3层,否则应考虑重构代码
  4. 性能考虑
    • 避免在循环嵌套中进行不必要的复杂计算
    • 尽量减少循环嵌套的层数,优化算法时间复杂度

8.6 综合应用示例

示例1:打印九九乘法表

for (int i = 1; i <= 9; i++) { // 外层循环控制行
    for (int j = 1; j <= i; j++) { // 内层循环控制列
        printf("%d×%d=%-2d ", j, i, i*j);
    }
    printf("\n");
}

示例2:判断素数

int num;
cout << "请输入一个正整数:";
cin >> num;
bool isPrime = true;

if (num <= 1) {
    isPrime = false;
} else {
    for (int i = 2; i * i <= num; i++) {
        if (num % i == 0) {
            isPrime = false;
            break;
        }
    }
}

if (isPrime) {
    cout << num << "是素数" << endl;
} else {
    cout << num << "不是素数" << endl;
}

第9章 常用数学函数

9.1 概述

在C++编程中,数学函数是实现数值计算和科学运算的重要工具。GESP-C++二级考试中,掌握这些常用数学函数对于解决各种计算问题至关重要。

9.1.1 头文件包含

  • C语言:使用 <math.h><stdlib.h><time.h>
  • C++推荐:使用 <cmath><cstdlib><ctime>(位于 std 命名空间中)
  • 最佳实践:在C++中推荐使用 <cmath> 头文件,以符合C++标准规范

9.2 绝对值函数

绝对值函数用于获取一个数的绝对值,根据数据类型的不同有以下几种:

9.2.1 整数绝对值函数

#include <cstdlib>  // 或 <cmath>

int x = -5;
int abs_x = abs(x);  // 返回 5
  • int abs(int x):返回整数 x 的绝对值
  • 示例:abs(-5) 返回 5abs(3) 返回 3

9.2.2 长整数绝对值函数

long labs(long x);  // 返回长整数 x 的绝对值
  • 示例:labs(-100000L) 返回 100000L

9.2.3 浮点数绝对值函数

#include <cmath>

double x = -3.14;
double abs_x = fabs(x);  // 返回 3.14
  • double fabs(double x):返回双精度浮点数 x 的绝对值
  • 示例:fabs(-3.14) 返回 3.14fabs(2.718) 返回 2.718

9.3 幂函数

幂函数主要用于进行幂运算和求平方根等操作。

9.3.1 幂运算函数

#include <cmath>

double result1 = pow(2.0, 3.0);  // 2^3 = 8.0
double result2 = pow(10.0, 2.0); // 10^2 = 100.0
  • double pow(double x, double y):返回 x 的 y 次方(x^y)
  • 注意:当 x 为负数且 y 不是整数时,结果可能为 NaN(非数字)

9.3.2 平方根函数

#include <cmath>

double sqrt_16 = sqrt(16.0);  // 返回 4.0
double sqrt_2 = sqrt(2.0);    // 约返回 1.4142
  • double sqrt(double x):返回 x 的平方根
  • 重要限制x 必须大于等于 0,否则结果未定义或返回 NaN
  • 示例:sqrt(16.0) 返回 4.0sqrt(2.0) 约返回 1.4142

9.4 取整与四舍五入函数

9.4.1 向上取整函数

#include <cmath>

double ceil1 = ceil(3.2);   // 返回 4.0
double ceil2 = ceil(-2.8);  // 返回 -2.0
  • double ceil(double x):返回大于或等于 x 的最小整数(向上取整)
  • 示例:ceil(3.2) 返回 4.0ceil(-2.8) 返回 -2.0

9.4.2 向下取整函数

#include <cmath>

double floor1 = floor(3.8);   // 返回 3.0
double floor2 = floor(-1.2);  // 返回 -2.0
  • double floor(double x):返回小于或等于 x 的最大整数(向下取整)
  • 示例:floor(3.8) 返回 3.0floor(-1.2) 返回 -2.0

9.4.3 四舍五入函数

#include <cmath>

double round1 = round(3.2);   // 返回 3.0
double round2 = round(3.6);   // 返回 4.0
double round3 = round(-2.3);  // 返回 -2.0
double round4 = round(-2.6);  // 返回 -3.0
  • double round(double x):对 x 进行四舍五入,返回最接近 x 的整数
  • 注意:round 函数遵循"四舍六入五成双"规则(银行家舍入法)

9.5 取大取小函数

9.5.1 整数取大取小

// C++中可以使用algorithm头文件中的max/min函数
#include <algorithm>

int max_val = max(5, 8);  // 返回 8
int min_val = min(5, 8);  // 返回 5
  • max(a, b):返回两个整数 a 和 b 中的最大值
  • min(a, b):返回两个整数 a 和 b 中的最小值

9.5.2 浮点数取大取小

#include <cmath>

double fmax_val = fmax(3.14, 2.718);  // 返回 3.14
double fmin_val = fmin(3.14, 2.718);  // 返回 2.718
  • double fmax(double a, double b):返回两个浮点数 a 和 b 中的最大值
  • double fmin(double a, double b):返回两个浮点数 a 和 b 中的最小值
  • 优势:适用于浮点数,能更精准地处理浮点数比较
  • 示例:fmax(3.14, 2.718) 返回 3.14fmin(-2.5, 1.8) 返回 -2.5

9.8 C 与 C++ 中数学函数的联系与区别

9.8.1 联系

  • C++ 语言继承了 C 语言中所有的数学函数
  • 函数功能和使用方式基本一致

9.8.2 区别

  1. 头文件不同
    • C:<math.h><stdlib.h><time.h>
    • C++:<cmath><cstdlib><ctime>
  2. 命名空间
    • C++ 的 <cmath> 中函数通常位于 std 命名空间中
    • 可以使用 using namespace std;std:: 前缀调用
  3. 推荐用法
    • 在 C++ 中推荐使用 <cmath> 头文件,符合 C++ 标准规范
    • 可以使用 C 的头文件,但不符合 C++ 最佳实践

9.9 使用数学函数的注意事项

9.9.1 头文件包含

  • 必须包含相应的头文件

    // C++ 推荐方式
    #include <cmath>    // 数学函数
    #include <cstdlib>  // 随机函数、abs等
    #include <ctime>    // 时间函数
    

9.9.2 数据类型匹配

  • 注意参数和返回值类型
    • 大多数数学函数的参数和返回值为 double 类型
    • 随机函数 rand() 返回 int 类型
    • 注意类型匹配,避免精度损失

9.9.3 函数定义域

  • 关注函数的定义域
    • sqrt(x) 要求 x ≥ 0
    • pow(x, y) 当 x 为负数且 y 不是整数时,结果可能为 NaN
    • 若超出定义域,函数行为是未定义的,可能返回错误值或导致程序异常

9.9.4 随机函数的特性

  • 伪随机数rand() 生成的是伪随机数,序列可预测
  • 种子初始化必须用 srand() 初始化种子,否则默认种子为 1
  • 种子相同:相同种子会产生相同的随机数序列
  • 时间种子:推荐使用 srand(time(NULL)) 保证每次运行不同

9.9.5 精度问题

  • 浮点数精度:浮点数运算可能存在精度损失

    double result = sqrt(2.0);  // 结果可能不是精确的 √2
    
  • 比较浮点数:避免直接用 == 比较浮点数结果

    // 不推荐
    if (sqrt(4.0) == 2.0) { ... }
    
    // 推荐:使用容差比较
    const double EPSILON = 1e-6;
    if (fabs(sqrt(4.0) - 2.0) < EPSILON) { ... }