返回:0200 C++总目录 · 上一课:0201 Chap1 绪论 · 下一课:0203 Chap3 函数

1、资料清单

资料 内容 入口
教材 《C++语言程序设计(第4版)》Chap2,原书页码 35-79 抽取 Markdown 下载
课件 Chap2 课件,位于本地郑莉 C++ 资料目录 本地资料夹
例题源代码 C++V5 源代码 下载
VS2019 工程 C++V5 VS2019 solution 下载

本章的定位:从“知道 C++ 是什么”进入“能写出一个能运行的小程序”。主线是程序结构 → 类型与表达式 → 输入输出 → 顺序/选择/循环 → 自定义类型

2、颜色标注

颜色 含义 使用位置
蓝色 核心语法、定义 标识符、表达式、作用域、枚举
绿色 程序主线、推荐写法 int main()、现代 C++ 输入输出
黄色 易错点、边界条件 ===、整数除法、无符号下溢
红色 不建议继续沿用的旧写法 iostream.hvoid main()

3、学习目标

目标 要会到什么程度
程序结构 会写 #includemain 函数、语句、返回值
基本类型 分清整型、字符型、浮点型、布尔型和它们的基本取值特点
常量与变量 会用 const 定义常量,会声明和初始化变量
表达式 会计算算术、关系、逻辑、位运算表达式
输入输出 会用 cincout 完成简单交互
控制结构 会使用 ifswitchwhiledo whilefor
自定义类型 会定义简单结构体和枚举类型

4、章节目录

小节 内容 本节关键词
2.1 C++语言概述 程序结构、注释、命名空间
2.2 基本数据类型和表达式 类型、变量、常量、运算符
2.3 数据的输入与输出 cincout、格式控制
2.4 算法的基本控制结构 顺序、选择、循环
2.5 自定义数据类型 typedefenumstruct
2.6 变量与表达式执行原理 内存、作用域、存储类型

5、C++ 简单程序结构

一个最小的现代 C++ 程序可以写成:

1
2
3
4
5
6
#include <iostream>

int main() {
std::cout << "Hello, C++!" << std::endl;
return 0;
}
组成 作用
#include <iostream> 引入标准输入输出流库
int main() 程序入口,返回 int 表示程序结束状态
{ ... } 函数体
std::cout 标准输出流
return 0; 程序正常结束

教材中的旧写法 #include <iostream.h>void main() 在早期编译器中常见,但现代 C++ 推荐写成#include <iostream>int main()

6、标识符、常量与变量

6.1 标识符

标识符是程序中给变量、函数、类型等起的名字。

规则 说明
首字符 必须是字母或下划线
后续字符 可以是字母、数字或下划线
不能使用 关键字、空格、@- 等特殊符号
大小写 C++ 区分大小写,Scorescore 不同

例子:

1
2
合法:Program, _lock, test2, A_B_C_D
非法:-page, 3in1, @mail

6.2 常量与变量

概念 含义 例子
常量 程序运行期间值不改变 const double PI = 3.1416;
变量 程序运行期间值可以改变 int score = 85;

优先使用 const 定义常量,而不是宏 #defineconst 有类型,编译器可以检查错误,调试时也更清楚。

1
2
3
const double PI = 3.1416;
double radius = 2.0;
double area = PI * radius * radius;

7、基本数据类型

类型 常见名称 用途
整型 shortintlonglong long 表示整数
字符型 char 表示字符或小整数
浮点型 floatdoublelong double 表示小数
布尔型 bool 表示 truefalse
空类型 void 表示无返回值或无类型

不同平台上类型字节数可能不同,学习时用 sizeof 实测,不要死背某一个编译器的结果。

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <limits>

int main() {
std::cout << "int bytes: " << sizeof(int) << '\n';
std::cout << "double bytes: " << sizeof(double) << '\n';
std::cout << "int max: " << std::numeric_limits<int>::max() << '\n';
return 0;
}

8、表达式与运算符

8.1 表达式

表达式是由操作数和运算符组成、能够计算出一个值的式子。

1
x = 5 + 7;

这是一个表达式,计算后 x 得到 12,整个赋值表达式的值也为 12

8.2 常见运算符

类型 运算符 例子
算术运算 + - * / % 201 / 4201 % 4
关系运算 < <= > >= == != x == 3
逻辑运算 `! &&
位运算 `& ^ ~ << >>`
赋值运算 = += -= *= /= %= x += 2
自增自减 ++ -- i++++i

= 是赋值,== 才是相等判断。if (x = 3) 会先把 3 赋给 x,条件结果通常为真;if (x == 3) 才是在判断 x 是否等于 3

8.3 前置与后置自增

写法 含义
++i 先自增,再使用新值
i++ 先使用旧值,再自增
1
2
3
int a = 30;
int b = a++; // b=30, a=31
int c = ++a; // a=32, c=32

最终结果:

1
2
3
a = 32
b = 30
c = 32

9、输入输出

1
2
3
4
5
6
7
8
9
#include <iostream>

int main() {
int number;
std::cout << "请输入一个数字:";
std::cin >> number;
std::cout << "你输入的数字是:" << number << std::endl;
return 0;
}
对象 作用
std::cin 标准输入流,通常来自键盘
std::cout 标准输出流,通常输出到屏幕
>> 提取运算符,从输入流取数据
<< 插入运算符,把数据送到输出流
std::endl 换行并刷新缓冲区

10、控制结构

10.1 顺序结构

语句从上到下依次执行。

1
2
3
int a = 10;
int b = 20;
int sum = a + b;

10.2 选择结构

1
2
3
4
5
6
7
8
9
if (score >= 90) {
std::cout << "优";
} else if (score >= 80) {
std::cout << "良";
} else if (score >= 60) {
std::cout << "中";
} else {
std::cout << "差";
}

switch 适合处理离散分支:

1
2
3
4
5
6
7
8
9
10
switch (choice) {
case 'A':
std::cout << "增加";
break;
case 'Q':
std::cout << "退出";
break;
default:
std::cout << "无效输入";
}

10.3 循环结构

循环 特点
while 先判断,后执行,可能一次都不执行
do while 先执行,后判断,至少执行一次
for 初始化、条件、更新集中,适合计数循环
1
2
3
for (int n = 100; n <= 200; n += 2) {
std::cout << n << ' ';
}

10.4 breakcontinue

语句 作用
break 跳出整个循环或 switch
continue 结束本次循环,进入下一轮判断

11、自定义数据类型

11.1 结构体

1
2
3
4
5
6
7
8
struct DateTime {
int year;
int month;
int day;
int hour;
int minute;
int second;
};

结构体适合把多个相关字段组合在一起。

11.2 枚举

1
2
3
4
5
6
7
8
9
enum weekday {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
};

默认情况下,Sunday 的值为 0,后面依次加 1

12、作用域与存储类型

概念 含义
作用域 标识符在程序中有效的区域
局部变量 在函数或语句块内部定义,只在局部有效
全局变量 在函数外定义,具有文件作用域

变量常见存储类型:

存储类型 说明
auto 普通局部变量,通常位于栈上,现代 C++ 中 auto 也用于类型推断
register 建议变量放寄存器,现代 C++ 中基本不再手动使用
extern 声明外部变量或函数
static 静态存储期,程序运行期间一直存在

全局变量虽然方便,但容易让程序状态变乱。初学时能用局部变量解决,就尽量不要依赖全局变量。

13、本章代码复盘

下面这个小程序把本章大部分主线串起来:输入、常量、表达式、选择结构、循环和函数库。

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
#include <cctype>
#include <iostream>

int main() {
const int PASS = 60;
int score;

std::cout << "请输入成绩(0-100):";
std::cin >> score;

if (score < 0 || score > 100) {
std::cout << "成绩范围错误" << std::endl;
return 0;
}

if (score >= 90) {
std::cout << "等级:优" << std::endl;
} else if (score >= 80) {
std::cout << "等级:良" << std::endl;
} else if (score >= PASS) {
std::cout << "等级:中" << std::endl;
} else {
std::cout << "等级:差" << std::endl;
}

char again;
std::cout << "是否查看 ASCII 码 65-70?(Y/N):";
std::cin >> again;

if (std::toupper(static_cast<unsigned char>(again)) == 'Y') {
for (int code = 65; code <= 70; ++code) {
std::cout << code << " -> " << static_cast<char>(code) << '\n';
}
}

return 0;
}

14、课后习题答案

以下答案按现代 C++ 重新整理。教材原答案中的 iostream.hvoid main() 保留理解即可,自己复盘时建议使用本页写法。

2-1 C++ 语言有哪些主要特点和优点

C++ 的主要特点:

特点 说明
兼容 C 保留 C 的高效、灵活、接近底层等特点
支持面向对象 提供类、对象、封装、继承、多态
类型检查更强 相比 C,编译器能检查出更多类型错误
支持泛型编程 模板和 STL 支持复用算法与容器
可移植性较好 标准 C++ 程序可以在不同平台编译

一句话:C++ 既能接近底层,又能做抽象建模。

2-2 判断合法标识符

标识符 是否合法 原因
Program 合法 字母开头
-page 不合法 不能以 - 开头
_lock 合法 下划线开头可以
test2 合法 后续字符可以有数字
3in1 不合法 不能以数字开头
@mail 不合法 不能含 @
A_B_C_D 合法 字母和下划线组成

2-3 例 2.1 每条语句的作用

现代 C++ 写法:

1
2
3
4
5
6
7
#include <iostream>             // 引入标准输入输出库

int main() { // 程序入口
std::cout << "Hello!\n"; // 输出 Hello 并换行
std::cout << "Welcome to C++!\n"; // 输出欢迎信息并换行
return 0; // 程序正常结束
}

运行结果:

1
2
Hello!
Welcome to C++!

2-4 使用 const 而不是 #define 的好处

const 的好处:

好处 说明
有类型 编译器可以做类型检查
作用域清楚 可以放在局部作用域中
便于调试 调试器中可以看到常量名
更符合 C++ 风格 和类、命名空间、模板配合更自然

2-5 声明常量 PI 并赋给浮点变量

1
2
const double PI = 3.1416;
double a = PI;

2-6 枚举中 Blue 的值

1
enum COLOR { WHITE, BLACK = 100, RED, BLUE, GREEN = 300 };

枚举值依次为:

枚举项
WHITE 0
BLACK 100
RED 101
BLUE 102
GREEN 300

所以 BLUE = 102

2-7 注释的作用和写法

注释用于解释程序意图,提高可读性。编译时注释会被忽略,不影响最终可执行程序逻辑。

注释 形式 特点
单行注释 // 注释内容 // 到行尾都是注释
多行注释 /* 注释内容 */ 可跨多行,但不能随意嵌套

2-8 什么是表达式

表达式是能够计算出值的式子。

1
x = 5 + 7;

它是表达式,执行后 x 的值为 12,整个赋值表达式的值也是 12

2-9 表达式求值

表达式 结果 说明
201 / 4 50 两个整数相除,结果仍为整数,小数部分截断
201 % 4 1 取余数
201 / 4.0 50.25 有浮点数参与,结果为浮点数

2-10 自增表达式求值

1
2
3
a = 30;
b = a++;
c = ++a;

过程:

语句 结果
b = a++ 先把 30 赋给 b,再让 a 变成 31
c = ++a 先让 a 变成 32,再把 32 赋给 c

最终:

1
2
3
a = 32
b = 30
c = 32

2-11 for 循环中能否初始化多个变量

可以,用逗号分隔。

1
2
3
for (int x = 0, y = 10; x < 100; ++x, ++y) {
// ...
}

2-12 循环结束后 n 的值

1
2
3
int n;
for (n = 0; n < 100; n++) {
}

循环结束时,n = 100

2-13 用三种循环实现 100200,步长为 2

for

1
2
3
for (int n = 100; n <= 200; n += 2) {
std::cout << n << ' ';
}

while

1
2
3
4
5
int n = 100;
while (n <= 200) {
std::cout << n << ' ';
n += 2;
}

do while

1
2
3
4
5
int n = 100;
do {
std::cout << n << ' ';
n += 2;
} while (n <= 200);

2-14 if (x = 3)if (x == 3) 的区别

写法 含义
if (x = 3) 3 赋给 x,表达式值为 3,条件为真
if (x == 3) 判断 x 是否等于 3

这是 C++ 初学最常见错误之一:判断相等必须写 ==,不要写成 =

2-15 作用域、局部变量、全局变量

概念 说明
作用域 标识符在程序正文中有效的范围
局部变量 在函数或代码块内部定义,只在该范围内有效
全局变量 在函数外部定义,从定义处到文件结束范围内有效

全局变量可以被多个函数访问,但应谨慎使用。

2-16 把较小的值赋给原本较大的变量

1
2
3
4
5
if (x > y) {
x = y;
} else if (y > x) {
y = x;
}

执行后,xy 都等于原来两者中的较小值。

2-17 修改程序错误并给出结果

修正后的现代 C++ 程序:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main() {
int i;
int j;

i = 10; // 给 i 赋值
j = 20; // 给 j 赋值

std::cout << "i + j = " << i + j << std::endl;
return 0;
}

输出:

1
i + j = 30

主要错误:

错误 修改
缺少 { int main() {
int i 缺少分号 int i;
注释没有正确闭合 改成 // 或完整的 /* ... */
字符串引号不完整 "i + j = "
void main() 改成 int main()

2-18 输入一个数字再显示

1
2
3
4
5
6
7
8
9
#include <iostream>

int main() {
int number;
std::cout << "请输入一个数字:";
std::cin >> number;
std::cout << "你输入的数字是:" << number << std::endl;
return 0;
}

2-19 显示各种数据类型字节数

C++ 常见基本类型包括整型、字符型、浮点型、布尔型等。具体值域与平台、编译器有关,可以用 sizeofnumeric_limits 查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <limits>

int main() {
std::cout << "char: " << sizeof(char) << " byte\n";
std::cout << "short: " << sizeof(short) << " bytes\n";
std::cout << "int: " << sizeof(int) << " bytes\n";
std::cout << "long: " << sizeof(long) << " bytes\n";
std::cout << "long long: " << sizeof(long long) << " bytes\n";
std::cout << "float: " << sizeof(float) << " bytes\n";
std::cout << "double: " << sizeof(double) << " bytes\n";
std::cout << "bool: " << sizeof(bool) << " byte\n";

std::cout << "int range: "
<< std::numeric_limits<int>::min()
<< " ~ "
<< std::numeric_limits<int>::max()
<< std::endl;

return 0;
}

2-20 打印 ASCII 码 32~127 的字符

1
2
3
4
5
6
7
8
#include <iostream>

int main() {
for (int code = 32; code <= 127; ++code) {
std::cout << code << " -> " << static_cast<char>(code) << '\n';
}
return 0;
}

ASCII 127 是 DEL 控制字符,通常不可见。真正可打印字符一般是 32~126

2-21 无符号整数输出观察

1
2
3
4
5
6
unsigned int x;
unsigned int y = 100;
unsigned int z = 50;

x = y - z; // 50
x = z - y; // 无符号下溢

unsigned int 为 32 位,结果通常是:

1
2
Difference is: 50
Now difference is: 4294967246

原因:z - y 本来是 -50,但无符号整数不能表示负数,于是按模 2^32 回绕:

1
2^32 - 50 = 4294967246

2-22 i++++i 的输出差别

核心结论:

表达式 使用值 自增时机
i++ 旧值 使用后再加 1
++i 新值 先加 1 再使用

关键片段:

1
2
std::cout << myAge++ << std::endl;   // 先输出,再增加
std::cout << ++yourAge << std::endl; // 先增加,再输出

若初始值都为 39,最终两者都会变成 41,但中途输出不同。

2-23 什么是常量和变量

概念 含义
常量 程序运行过程中值不能改变的量
变量 程序运行过程中值可以改变的量
1
2
const int MAX_SCORE = 100;
int score = 85;

2-24 变量有哪几种存储类型

存储类型 说明
auto 自动存储,普通局部变量常见形式
register 建议放入寄存器,现代 C++ 很少手动使用
extern 声明外部变量
static 静态存储,程序运行期间一直存在

2-25 逻辑表达式结果

表达式 结果
2 < 3 && 6 < 9 true
!(4 < 7) false
`!(3 > 5)

2-26 位运算表达式结果

a = 1b = 2c = 3

表达式 结果 说明
`a b - c` -1
a ^ b & -c 1 & 优先级高于 ^b & -c = 0
`a & b c` 3
`a b & c` 3

2-27 位运算表达式结果

a = 1

表达式 结果
`!a a`
`~a a`
a ^ a 0
a >> 2 0

2-28 判断是否正在下雨

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
#include <cctype>
#include <iostream>

int main() {
char flag;

while (true) {
std::cout << "现在正在下雨吗?(Y/N): ";
std::cin >> flag;

flag = static_cast<char>(std::toupper(static_cast<unsigned char>(flag)));

if (flag == 'Y') {
std::cout << "现在正在下雨。" << std::endl;
break;
}

if (flag == 'N') {
std::cout << "现在没有下雨。" << std::endl;
break;
}
}

return 0;
}

2-29 根据成绩判断等级

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
#include <iostream>

int main() {
int score;
std::cout << "你考试考了多少分?(0~100): ";
std::cin >> score;

if (score < 0 || score > 100) {
std::cout << "分数值必须在 0 到 100 之间!" << std::endl;
return 0;
}

switch (score / 10) {
case 10:
case 9:
std::cout << "你的成绩为优!" << std::endl;
break;
case 8:
std::cout << "你的成绩为良!" << std::endl;
break;
case 7:
case 6:
std::cout << "你的成绩为中!" << std::endl;
break;
default:
std::cout << "你的成绩为差!" << std::endl;
break;
}

return 0;
}

2-30 菜单程序

2-30(1)使用 if else

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
#include <cctype>
#include <iostream>

int main() {
char choice;

while (true) {
std::cout << "Menu: A(dd) D(elete) S(ort) Q(uit), Select one: ";
std::cin >> choice;

choice = static_cast<char>(std::toupper(static_cast<unsigned char>(choice)));

if (choice == 'A') {
std::cout << "数据已经增加。" << std::endl;
continue;
} else if (choice == 'D') {
std::cout << "数据已经删除。" << std::endl;
continue;
} else if (choice == 'S') {
std::cout << "数据已经排序。" << std::endl;
continue;
} else if (choice == 'Q') {
break;
}
}

return 0;
}

2-30(2)使用 switch

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
#include <cctype>
#include <iostream>

int main() {
char choice;

while (true) {
std::cout << "Menu: A(dd) D(elete) S(ort) Q(uit), Select one: ";
std::cin >> choice;

switch (std::toupper(static_cast<unsigned char>(choice))) {
case 'A':
std::cout << "数据已经增加。" << std::endl;
break;
case 'D':
std::cout << "数据已经删除。" << std::endl;
break;
case 'S':
std::cout << "数据已经排序。" << std::endl;
break;
case 'Q':
return 0;
default:
std::cout << "无效选择。" << std::endl;
break;
}
}
}

2-31 用穷举法找出 1~100 间质数

为了避免三段代码太重复,先写一个判断质数的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
bool isPrime(int n) {
if (n < 2) {
return false;
}

for (int divisor = 2; divisor * divisor <= n; ++divisor) {
if (n % divisor == 0) {
return false;
}
}

return true;
}

for 循环版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

bool isPrime(int n) {
if (n < 2) return false;
for (int divisor = 2; divisor * divisor <= n; ++divisor) {
if (n % divisor == 0) return false;
}
return true;
}

int main() {
for (int n = 1; n <= 100; ++n) {
if (isPrime(n)) {
std::cout << n << ' ';
}
}
return 0;
}

while 循环版本:

1
2
3
4
5
6
7
int n = 1;
while (n <= 100) {
if (isPrime(n)) {
std::cout << n << ' ';
}
++n;
}

do while 循环版本:

1
2
3
4
5
6
7
int n = 1;
do {
if (isPrime(n)) {
std::cout << n << ' ';
}
++n;
} while (n <= 100);

输出:

1
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

2-32 比较 breakcontinue

语句 作用 常见场景
break 结束整个循环或跳出 switch 找到目标后停止搜索
continue 结束本次循环,进入下一轮 跳过不符合条件的数据

2-33 定义表示时间的结构体

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
#include <iostream>

struct DateTime {
int year;
int month;
int day;
int hour;
int minute;
int second;
};

int main() {
DateTime t;

std::cout << "请输入年 月 日 时 分 秒:";
std::cin >> t.year >> t.month >> t.day
>> t.hour >> t.minute >> t.second;

std::cout << t.year << "年"
<< t.month << "月"
<< t.day << "日 "
<< t.hour << ":"
<< t.minute << ":"
<< t.second << std::endl;

return 0;
}

2-34 猜数字程序

while 版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

int main() {
const int answer = 18;
int guess = 0;

while (guess != answer) {
std::cout << "请猜这个数的值为多少?(1~100): ";
std::cin >> guess;

if (guess < answer) {
std::cout << "你猜的值太小了!" << std::endl;
} else if (guess > answer) {
std::cout << "你猜的值太大了!" << std::endl;
} else {
std::cout << "你猜对了!" << std::endl;
}
}

return 0;
}

do while 版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

int main() {
const int answer = 18;
int guess;

do {
std::cout << "请猜这个数的值为多少?(1~100): ";
std::cin >> guess;

if (guess < answer) {
std::cout << "你猜的值太小了!" << std::endl;
} else if (guess > answer) {
std::cout << "你猜的值太大了!" << std::endl;
} else {
std::cout << "你猜对了!" << std::endl;
}
} while (guess != answer);

return 0;
}

2-35 定义 weekday 枚举类型并测试赋值

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
#include <iostream>

enum weekday {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
};

int main() {
weekday d = Thursday;
int i;

std::cout << "d = " << d << std::endl;

i = d; // 枚举值可以隐式转换为 int
std::cout << "i = " << i << std::endl;

d = static_cast<weekday>(6);
std::cout << "d = " << d << std::endl;

d = weekday(4);
std::cout << "d = " << d << std::endl;

return 0;
}

输出:

1
2
3
4
d = 4
i = 4
d = 6
d = 4

普通 enum 可以隐式转换成 int,但 int 赋给枚举变量通常需要显式转换。后续工程里更推荐使用 enum class,类型边界更清楚。

15、本章复盘任务

  1. 手写一个完整 C++ 程序,包含输入、输出、iffor
  2. 重新计算 2-92-102-252-262-27 的结果。
  3. 2-282-292-302-312-34 的程序各运行一遍。
  4. 总结 whiledo whilefor 分别适合什么场景。
  5. 用自己的话解释:为什么 const#define 更适合 C++。