Appearance
第6章 数据类型转换
🎯 本章学习目标
学完本章,你将能够:
- ✅ 说出类型转换的两种分类(隐式/强制)及区别
- ✅ 背出 C++ 类型提升顺序(char→int→long long→float→double)
- ✅ 熟练判断整数除法 vs 浮点除法的结果
- ✅ 掌握赋值转换的三条规则(截断、低8位、安全提升)
- ✅ 掌握字符按 ASCII 码参与运算的规律
- ✅ 理解 bool 类型的"非0即真"与转换规则
- ✅ 分清
(double)5/2和(double)(5/2)的区别 - ✅ 熟练写出平均分保留两位小数的正确代码
- ✅ 能做表达式类型推断题(如
1+2.0+'A')
🗺️ 本章知识图谱
数据类型转换
├── 隐式转换(自动)
│ ├── 混合运算提升:低→高(char→int→double)
│ ├── 整数除法陷阱(5/2=2,不是2.5)
│ ├── 赋值转换:右边→左边的类型
│ ├── 字符运算:按ASCII码提升为int
│ └── bool转换:非0→true,0→false
├── 强制转换(手动)
│ ├── C风格:(类型)值 如 (int)3.9
│ ├── C++风格:static_cast<类型>(值)
│ ├── 括号陷阱:(double)(5/2) vs (double)5/2
│ └── 截断永远不四舍五入
├── 表达式类型推断
│ ├── 结果类型=最高类型
│ ├── 从左到右,每步就地转换
│ └── 优先级影响运算顺序
└── 典型应用
├── 求平均分(转double避免整数除法)
├── 大小写转换(±32)
├── 数字字符转整数('5'-'0')
└── 输出格式控制(fixed+setprecision)一、什么是数据类型转换?
程序里的数据有不同类型:整数 int、小数 double/float、字符 char、字符串 str……当不同类型的数据混在一起运算或赋值时,就需要把一种类型"变成"另一种类型,这就是类型转换。
类型转换分两种:
| 分类 | 别名 | 触发方式 | 例子 |
|---|---|---|---|
| 隐式转换 | 自动转换 | 编译器/解释器自动完成,代码里看不出来 | 1 + 2.0、int a = 3.9; |
| 显式转换 | 强制转换 | 程序员手动写出转换指令 | (int)3.9、int("123") |
一句话记忆:隐式转换是"系统偷偷帮你转",强制转换是"你明确命令它转"。
二、C++ 的隐式类型转换
2.1 混合运算:向"高类型"自动提升
C++ 中不同类型的数据混合运算时,所有数据会先统一转换成表示范围更大、精度更高的那种类型,再进行运算。类型"高低"顺序为:
char / short → int → unsigned int → long → float → double
(低) (高)口诀:矮个子向高个子看齐。只要表达式里有一个 double,整个表达式的结果就是 double。
cpp
#include <iostream>
using namespace std;
int main() {
int a = 1;
double b = 2.0;
// int + double:a 先被提升为 double,结果是 double
cout << a + b << endl; // 输出:3(值为3.0,cout默认不显示小数点后的0)
// int * double:同理,结果 double
cout << a * 2.5 << endl; // 输出:2.5
// char 参与运算:先提升为 int(按ASCII码),结果是 int
cout << 'A' + 1 << endl; // 输出:66('A'的ASCII码是65,65+1=66)
// int + int + double:从左到右,1+2 得 int 3,3 再与 double 相加 → double
cout << 1 + 2 + 2.0 << endl; // 输出:5
return 0;
}高频考点 🔥: 判断表达式结果类型,看表达式中最高的那个类型。
1 + 2.0 + 'A'里最高是double,所以整个表达式是 double 类型:先算1+2.0→ 3.0,再算3.0 + 'A'('A' 提升为 65)→ 68.0。
2.2 整数除法:二级第一大陷阱
两个整数做除法 /,C++ 执行整数除法:结果还是整数,小数部分被直接截断(向零取整)。只要有一个操作数是小数,就做浮点除法。
cpp
#include <iostream>
using namespace std;
int main() {
cout << 5 / 2 << endl; // 输出:2 (整数除法,0.5被截断!)
cout << 5.0 / 2 << endl; // 输出:2.5 (有double,浮点除法)
cout << 5 / 2.0 << endl; // 输出:2.5
cout << 5.0 / 2.0 << endl; // 输出:2.5
// ⚠️ 注意运算顺序!类型转换只发生在"当下参与运算"的两个数之间
cout << 1.0 * 5 / 2 << endl; // 输出:2.5 (先 1.0*5=5.0,再 5.0/2=2.5)
cout << 5 / 2 * 1.0 << endl; // 输出:2 (先 5/2=2 整数除法!再 2*1.0=2.0)
// 求平均数的经典错误
int total = 10, n = 3;
cout << total / n << endl; // 输出:3 ❌ 想要3.33却得到3
cout << (double)total / n << endl; // 输出:3.33333 ✅ 先把total转成double
return 0;
}易错点 ⚠️:
5/2*1.0 = 2而1.0*5/2 = 2.5!整数除法在"两个 int 相除"的那一刻就已经截断了,后面再乘 1.0 也救不回来。编程题求平均分、求比例时,一定要让除法的某一边提前变成小数。
2.3 赋值转换:右边听左边的
赋值时,= 右侧的值会自动转换成左侧变量的类型:
double → int:截断小数部分(不是四舍五入!)int → char:按常见编译器取该整数的低 8 位(标准将此列为实现定义行为,考试按常见编译器结果作答)int → double:自动补.0,安全无损失
cpp
#include <iostream>
using namespace std;
int main() {
int a = 3.99; // double → int,截断小数
cout << a << endl; // 输出:3(不是4!截断不四舍五入)
double b = 5; // int → double,自动变小数
cout << b << endl; // 输出:5(即5.0)
char c = 65; // int → char,65 对应 'A'
cout << c << endl; // 输出:A
char c2 = 322; // 322 的二进制低8位是 66(322 = 256 + 66)
cout << (int)c2 << " " << c2 << endl; // 输出:66 B
int x = 'B'; // char → int,取ASCII码
cout << x << endl; // 输出:66
return 0;
}易错点 ⚠️:
int a = 3.99;结果是 3,截断永远"向零靠拢",不会四舍五入。负数同理:int(-2.8)得 -2。把超出范围的整数赋给 char 会只保留低 8 位(322→66),这是选择题常考的"意外结果"。
2.4 字符参与运算:按 ASCII 码
结合上一章 ASCII 编码知识:char 一旦参与算术运算,就先提升为 int,使用它的 ASCII 码值参与计算。
cpp
#include <iostream>
using namespace std;
int main() {
cout << 'A' + 1 << endl; // 输出:66 (65+1,结果是int不是char)
cout << (char)('A' + 1) << endl;// 输出:B (强制转回char才显示字符)
cout << 'a' - 'A' << endl; // 输出:32 (大小写字母ASCII码差32)
// 大小写互换的经典写法
char ch = 'a';
cout << (char)(ch - 32) << endl;// 输出:A (小写转大写)
char ch2 = 'Q';
cout << (char)(ch2 + 32) << endl;// 输出:q (大写转小写)
// 数字字符转数值:'5' - '0' = 5
cout << '5' - '0' << endl; // 输出:5
cout << (char)('0' + 7) << endl;// 输出:7 (数值7转数字字符)
return 0;
}高频考点 🔥: 三个必背算式:① 大小写转换
小写 - 32 = 大写、大写 + 32 = 小写;② 数字字符转整数'5' - '0' = 5;③ 判断字符ch是否为大写字母:ch >= 'A' && ch <= 'Z'。注意:字符做算术的结果是 int,想输出字符必须再转回 char。
2.5 bool 类型的转换规则 ⭐⭐⭐⭐
二级考试里 bool 和 int/double 之间的转换也常考,规则很简单:
其他类型 → bool:非 0 即真
- 任何非 0 的数 →
true(1) - 0 →
false(0)
bool → 其他类型:true=1, false=0
true→ 整数 1 / 小数 1.0false→ 整数 0 / 小数 0.0
cpp
#include <iostream>
using namespace std;
int main() {
// 其他类型 → bool(非0即真)
bool a = 5; // 非0 → true
cout << a << endl; // 输出:1(cout输出bool默认显示1或0)
bool b = 0; // 0 → false
cout << b << endl; // 输出:0
bool c = -3.14; // 非0(即使是负数和小数)→ true
cout << c << endl; // 输出:1
// bool → int/double
int x = true; // true → 1
double y = false; // false → 0.0
cout << x << " " << y << endl; // 输出:1 0
// 经典考题:true + true = ?
cout << (true + true) << endl; // 输出:2(bool提升为int,1+1=2)
cout << (true * 5) << endl; // 输出:5(true提升为1,1*5=5)
return 0;
}🔥 高频考点:
true + true的结果是 2(不是 true!)。因为两个 bool 做算术运算时,会先提升为 int(1 和 1),然后相加得 2。同理false + true = 1。
💡 记忆口诀:非 0 即真,真就是 1,假就是 0。bool 参与算术就按整数 1 和 0 来算。
三、C++ 的强制类型转换
当自动转换不合心意时,可以手动指定转换。C++ 有两种写法:
写法一(C 风格,考试最常见): (类型)表达式
写法二(C++ 标准风格): static_cast<类型>(表达式)
cpp
#include <iostream>
using namespace std;
int main() {
// ① double → int:截断小数,不四舍五入
cout << (int)3.9 << endl; // 输出:3
cout << (int)3.99 << endl; // 输出:3(不是4!)
cout << static_cast<int>(3.9) << endl; // 输出:3(标准写法,效果相同)
// ② int → double:让整数除法变浮点除法
cout << (double)5 / 2 << endl; // 输出:2.5 先把5转成5.0,再除以2
cout << (double)(5 / 2) << endl; // 输出:2 ⚠️ 先算5/2=2,再把2转成2.0!
// ③ int ↔ char:借助ASCII码
cout << (char)65 << endl; // 输出:A
cout << (int)'A' << endl; // 输出:65
// ④ 负数整数除法:向零截断(结果向0靠拢)
cout << -7 / 2 << endl; // 输出:-3 (-3.5向零截断为-3)
cout << 7 / -2 << endl; // 输出:-3
return 0;
}高频考点 🔥:
(double)5/2与(double)(5/2)只差一对括号,结果却不同:前者 2.5,后者 2!强制转换只作用于"紧跟它的那个量/括号里的整体"。判断时先算括号内、再看转换时机。
易错点 ⚠️: 无论是隐式还是强制,浮点数转整数都是截断(砍掉小数部分),
(int)3.99 = 3,绝不四舍五入。负数除法向零截断:-7/2 = -3(而不是 -4)。 取余运算符%的结果符号与被除数相同,例如-7 % 2的结果是-1,不是1。
四、表达式类型推断专项(典型考法)
考试常给一个混合表达式,让你判断结果类型与值。抓住两条规则:① 结果类型 = 表达式中最高类型;② 从左到右、每一步就地转换。
| 表达式 | C++ 结果 |
|---|---|
5 / 2 | int,2 |
5 // 2 | ⚠️ C++ 没有整除运算符 //:此处 // 被当作注释,表达式实际只有 5 |
5.0 / 2 | double,2.5 |
1 + 2.0 | double,3 |
1 + 2.0 + 'A' | double,68(3.0+65) |
'A' + 1 | int,66 |
'a' - 'A' | int,32 |
(int)3.99 | int,3 |
-7 / 2 | int,-3(向零截断) |
"123" + 456 | ⚠️ 不是拼接:"123" 是 const char*,+ 456 是指针偏移(越界无意义);C++ 拼接字符串要用 string |
高频考点 🔥:
1 + 2.0 + 'A'是"明星题":C++ 中 'A' 提升为 ASCII 码 65,结果 double 类型的 68;
五、📝 实战练习
练习题 1(程序阅读题)
题目: 阅读以下程序,写出 7 行输出:
cpp
#include <iostream>
using namespace std;
int main() {
int a = 5;
double b = 2.0;
cout << a / 2 << endl; // 行1
cout << a / b << endl; // 行2
cout << (double)a / 2 << endl; // 行3
cout << (double)(a / 2) << endl; // 行4
cout << (int)3.99 << endl; // 行5
char c = 'A';
cout << c + 1 << endl; // 行6
cout << (char)(c + 1) << endl; // 行7
return 0;
}🔑 点击查看答案与解析
答案:
2
2.5
2.5
2
3
66
B解析:
- 行1:
5/2两个 int 相除,整数除法截断 → 2; - 行2:
5 / 2.0,有 double 参与,浮点除法 → 2.5; - 行3:先把 a 转成 5.0,再
5.0/2→ 2.5; - 行4:先算括号内
5/2 = 2(已截断!),再把 2 转成 double → 2; - 行5:截断小数,不四舍五入 → 3;
- 行6:
'A'按 ASCII 码 65 参与运算,结果是 int → 66; - 行7:66 强制转回 char,对应字符 → B。
考点:整数除法、强制转换的时机、字符算术。
练习题 2(编程题)
题目: 输入三门课的成绩(整数,0~100),输出平均分,保留两位小数。
输入样例:
90 80 70输出样例:
80.00🔑 点击查看答案与解析
C++ 参考代码:
cpp
#include <iostream>
#include <iomanip> // setprecision 所需头文件
using namespace std;
int main() {
int a, b, c;
cin >> a >> b >> c;
// 关键:除以 3.0(double)而不是 3(int),否则整数除法丢掉小数!
double avg = (a + b + c) / 3.0;
cout << fixed << setprecision(2) << avg << endl; // 固定两位小数
return 0;
}解析:
- C++ 最大的坑:
(a+b+c)/3是整数除法,80.0 会变成 80、253/3 会变成 84;必须写/ 3.0或先(double)(a+b+c); - 输入
91 85 77时,输出84.33(253/3 = 84.333…),可自行上机验证。
练习题 3(单选题)
题目: 以下关于 C++ 类型转换的说法,正确的是( )
① true + true 的结果是 true(布尔值) ② int a = 3.99; 变量 a 的值是 4(四舍五入) ③ 5 / 2 * 1.0 的结果是 2.0 ④ 'A' + 1 的结果类型是 int,值为 66
A. ①② B. ②③ C. ③④ D. ①④
🔑 点击查看答案与解析
答案: C
解析:
- ① 错误 ❌:
true + true中两个 bool 都提升为 int(1 和 1),相加结果是 int 类型的 2,不是 true; - ② 错误 ❌:
double → int是截断小数部分,3.99 截断后是 3,不是 4,截断永远不四舍五入; - ③ 正确 ✅:从左到右运算,先算
5/2 = 2(整数除法,已截断!),再算2 * 1.0 = 2.0,结果是 2.0; - ④ 正确 ✅:char 参与算术运算会整型提升为 int,
'A'(65) + 1 = 66,类型为 int。
选 C(③④)。
💡 记忆口诀:bool 相加变整数、截断不是四舍五入、整数除法先截断再提升。
练习题 4(判断题)
题目: 判断下列说法是否正确,正确的打 ✓,错误的打 ×。
① 在 C++ 中,7 / 2 的结果是 3.5。( )
② 把 int 值 322 赋给 char 变量,在常见编译器上结果为 66(低 8 位)。( )
③ (double)5 / 2 和 (double)(5 / 2) 的结果相同,都是 2.5。( )
④ false + 5 的结果是 5。( )
⑤ 表达式 1 + 2.0 + 'A' 的结果类型是 double,值为 68.0。( )
🔑 点击查看答案与解析
答案: ① × ② ✓ ③ × ④ ✓ ⑤ ✓
解析:
- ① ×:两个 int 相除是整数除法,结果为 3(小数部分被截断);
- ② ✓:322 = 256 + 66,低 8 位 = 66,对应字符
'B'; - ③ ×:
(double)5/2先把 5 转成 5.0 再除,得 2.5;(double)(5/2)先算括号内5/2=2再转 double,得 2.0。括号位置决定转换时机,结果完全不同! - ④ ✓:
false提升为 int 0,0 + 5 = 5; - ⑤ ✓:
1 + 2.0 = 3.0(double),再与'A'(提升为 65)相加,结果为 double 类型的 68.0。
练习题 5(程序阅读题)
题目: 阅读以下 C++ 程序,写出 6 行输出:
cpp
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 3;
double x = 2.5;
cout << a / b << endl; // 行1
cout << 1.0 * a / b << endl; // 行2
cout << a / b * 1.0 << endl; // 行3
cout << (double)a / b << endl; // 行4
cout << a % b << endl; // 行5
cout << 'a' - 'A' + '0' << endl; // 行6
return 0;
}🔑 点击查看答案与解析
答案:
3
3.33333
3
3.33333
1
80解析:
- 行1:
10/3两个 int,整数除法 → 3(截断小数); - 行2:先算
1.0 * 10 = 10.0(double),再算10.0 / 3(浮点除法)→ 3.33333; - 行3:先算
10/3 = 3(整数除法!已截断),再算3 * 1.0 = 3.0→ 3(⚠️ 经典陷阱!); - 行4:先把 a 强转 double → 10.0,再除以 3 → 3.33333(这是求平均分的正确写法);
- 行5:
10 % 3取余 = 1(10 = 3×3 + 1); - 行6:
'a'-'A' = 32,再加'0'(48) = 80(char 算术的结果都是 int)。
🔥 核心考点:整数除法的时机——只要两个 int 一碰
/,小数立刻没了,后面再乘多少 double 也救不回来。想得到小数结果,必须让除法发生前就有一边是 double。
练习题 6(程序阅读题)
题目: 阅读以下 C++ 程序,写出 5 行输出:
cpp
#include <iostream>
using namespace std;
int main() {
int n = 3.99;
cout << n << endl; // 行1
char c = 353;
cout << (int)c << " " << c << endl; // 行2
bool b1 = 0, b2 = 5, b3 = -2.7;
cout << b1 << " " << b2 << " " << b3 << endl; // 行3
double d = true;
cout << d << endl; // 行4
int x = 'C' - 'A' + '0';
cout << (char)x << endl; // 行5
return 0;
}🔑 点击查看答案与解析
答案:
3
97 a
0 1 1
1
2解析:
- 行1:
double → int截断小数 → 3(不是 4!); - 行2:353 = 256 + 97,取低 8 位 = 97,对应字符
'a'→ 输出97 a; - 行3:bool 转换"非 0 即真"——
0→false(0)、5→true(1)、-2.7→true(1)(负数也是非 0)→0 1 1; - 行4:
true → double= 1.0,cout 默认不显示末尾 0 → 输出1; - 行5:
'C'-'A' = 2,2 + '0'= 2 + 48 = 50,50 号字符是'2'→ 输出2(数字字符与数值相差 '0'=48)。
练习题 7(编程题)
题目: 输入一个小写字母,将它向后偏移 3 位后输出(凯撒密码简化版)。例如输入 a 输出 d,输入 y 输出 b(超出 z 时绕回开头)。
输入样例1:
a输出样例1:
d输入样例2:
y输出样例2:
b🔑 点击查看答案与解析
参考代码(C++):
cpp
#include <iostream>
using namespace std;
int main() {
char ch;
cin >> ch;
// 方法:先转成 0~25 的偏移量,+3 后对 26 取模,再转回字符
int offset = ch - 'a'; // 'a'→0, 'b'→1, ..., 'z'→25
offset = (offset + 3) % 26; // 向后移 3 位,超 z 就绕回(取模)
char result = 'a' + offset; // 偏移量转回字符
cout << result << endl;
return 0;
}
// 输入 a → 0+3=3 → 'd' ✅
// 输入 y → 24+3=27 → 27%26=1 → 'b' ✅解析要点:
- 利用
ch - 'a'把字母转成 0~25 的"序号",这是字符运算最经典的套路之一; (offset + 3) % 26实现"超出 z 绕回 a"的效果——取模运算让数字在范围内循环;- 最后用
'a' + offset把序号转回字符。这种"字符→序号→运算→字符"的模式在密码、排序题中反复出现。
练习题 8(编程题)
题目: 输入一个华氏温度 F(整数),输出对应的摄氏温度 C,公式为 C = 5 × (F − 32) / 9,结果保留两位小数。
输入样例:
100输出样例:
37.78🔑 点击查看答案与解析
参考代码(C++):
cpp
#include <iostream>
#include <iomanip> // setprecision 头文件
using namespace std;
int main() {
int f;
cin >> f;
// 关键:让除法变成浮点除法,避免整数截断
double c = 5.0 * (f - 32) / 9;
cout << fixed << setprecision(2) << c << endl;
return 0;
}
// 输入 100:5.0 × (100-32) / 9 = 5.0 × 68 / 9 = 340.0 / 9 = 37.777... ≈ 37.78 ✅解析要点:
- 公式中写
5.0而不是5,确保乘法结果是 double,后续除法就是浮点除法; - 如果写成
5 * (f - 32) / 9,全部是 int 运算,结果会被截断为整数 37; fixed << setprecision(2)固定输出两位小数,这是 C++ 格式化输出的标准写法,头文件为<iomanip>。
💡 生活比喻:类型转换就像"单位换算"——你不能直接用"厘米"加"米",得先统一单位再计算。
5.0就是先把整数"换算"成小数,再参与运算。
六、📊 考点总结表
| 考点 | 重要程度 | 出题形式 |
|---|---|---|
| C++ 混合运算自动提升(char/short→int→…→double) | ⭐⭐⭐⭐ | 选择/程序阅读 |
C++ 整数除法 5/2=2、浮点除法 5.0/2=2.5 | ⭐⭐⭐⭐⭐ | 选择/判断/编程 |
C++ 赋值截断 int a=3.99 → 3、int 转 char 取低8位 | ⭐⭐⭐⭐ | 程序阅读/选择 |
C++ 强制转换 (int)x、(double)x、(char)x、static_cast | ⭐⭐⭐⭐⭐ | 程序阅读/选择 |
(double)5/2 与 (double)(5/2) 的区别 | ⭐⭐⭐⭐ | 选择/程序阅读 |
字符按 ASCII 参与运算、大小写±32、'5'-'0' | ⭐⭐⭐⭐⭐ | 程序阅读/编程 |
表达式类型推断(如 1+2.0+'A') | ⭐⭐⭐⭐⭐ | 选择/程序阅读 |
⭐ 必背速记卡
┌─────────────────────────────────────────────────────┐
│ 1. 类型转换分两种:隐式自动转,强制手动转 │
│ 2. 混合运算向高看齐:char→int→float→double │
│ 3. 两int相除是整数除法,小数直接截断,不四舍五入 │
│ 4. 想得到小数结果,除法前先让一边变成 double │
│ 5. (double)5/2 = 2.5,(double)(5/2) = 2,括号很重要 │
│ 6. double→int 截断小数:(int)3.99 = 3 │
│ 7. int→char 取低8位:322→66,353→97 │
│ 8. char 参与算术自动提升为 int,按 ASCII 码运算 │
│ 9. 大小写差32:小写-32=大写,大写+32=小写 │
│ 10. 数字字符转数值:'5'-'0' = 5 │
│ 11. bool 非0即真:true=1, false=0 │
│ 12. true + true = 2(bool 提升为 int 相加) │
│ 13. 表达式结果类型 = 表达式中最高的类型 │
│ 14. 求平均分:(double)总分 / 人数,别忘转 double │
│ 15. 保留两位小数:fixed << setprecision(2) │
└─────────────────────────────────────────────────────┘