Skip to content

第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.0
  • false → 整数 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 / 2int,2
5 // 2⚠️ C++ 没有整除运算符 //:此处 // 被当作注释,表达式实际只有 5
5.0 / 2double,2.5
1 + 2.0double,3
1 + 2.0 + 'A'double,68(3.0+65)
'A' + 1int,66
'a' - 'A'int,32
(int)3.99int,3
-7 / 2int,-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)            │
└─────────────────────────────────────────────────────┘

百炼成钢,融会贯通