高质量 C++ 进制转换专题训练(含深度解析)
进制转换是计算机底层数据处理的核心能力,也是 C++ 编程中字符串操作、逻辑运算的典型应用场景。本专题通过分层训练(基础→进阶→工程实践),结合实际开发中的边界情况,帮助学习者构建完整的进制转换知识体系。
一、核心原理巩固(理论 + 手动推演)
题目 1:进制转换数学本质分析
请从 "位权表示法" 角度解释:为什么任意进制数都能转换为十进制?以二进制数101.11和十六进制数3A.5为例,写出其十进制展开式并计算结果。
关键知识点
- 位权公式:对于基数为
b的进制,第i位(整数部分从右往左为 0,1,2...,小数部分从左往右为 - 1,-2...)的位权为b^i - 小数转换核心:整数部分 "除基取余",小数部分 "乘基取整"
参考答案
-
数学本质:任意进制数均可表示为 "每位数字 × 对应位权" 的总和,而十进制是人类最易理解的中间媒介,因此可通过位权展开实现转换。
-
二进制
101.11转换:- 整数部分:
1×2² + 0×2¹ + 1×2⁰ = 4 + 0 + 1 = 5 - 小数部分:
1×2⁻¹ + 1×2⁻² = 0.5 + 0.25 = 0.75 - 结果:
5.75
- 整数部分:
-
十六进制
3A.5转换:- 整数部分:
3×16¹ + 10×16⁰ = 48 + 10 = 58 - 小数部分:
5×16⁻¹ = 5/16 = 0.3125 - 结果:
58.3125
- 整数部分:
题目 2:特殊值转换边界分析
以下场景在编程中需特别处理,请写出结果并说明理由:
- 十进制
0转换为二进制、八进制、十六进制的结果 - 二进制
11111111(8 位)作为无符号数和有符号数(补码)的十进制值 - 十六进制
0x7FFFFFFF(32 位)加 1 后的十进制结果及溢出原因
参考答案
-
0的转换结果均为"0"。理由:0 在任何进制下表示形式唯一,需单独处理避免转换逻辑(如除基取余)因商为 0 而无输出。 -
8 位
11111111:- 无符号数:
2⁷+...+2⁰=255 - 有符号数(补码):最高位为符号位(1 表示负),数值部分为
~255 + 1 = -1(补码转原码:取反 + 1)
- 无符号数:
-
0x7FFFFFFF(32 位有符号最大正数)加 1 后为0x80000000,对应十进制-2147483648。理由:32 位有符号数范围为-2³¹ ~ 2³¹-1,溢出后触发补码循环。
二、基础编程题(整数转换・工程化实现)
题目 1:十进制转 N 进制(支持 2-36 进制,含大小写控制)
题目描述
实现函数decimalToBase(int num, int base, bool uppercase),要求:
- 输入非负整数
num、基数base(2≤base≤36,36 进制用 A-Z 表示 10-35) - 输出对应的
base进制字符串,uppercase为true时用大写字母,否则用小写 - 处理边界:
num=0时输出"0"
示例
decimalToBase(35, 16, true)→"23"decimalToBase(35, 36, false)→"z"decimalToBase(0, 2, true)→"0"
核心难点解析
- 字符映射表设计:需覆盖 0-9、A-Z(或 a-z),可通过 ASCII 码动态生成(如
'0' + valfor 0-9,'A' + val - 10for 10+) - 余数存储与反转:因除基取余得到的是低位到高位,需用栈或字符串反转处理
参考代码
cpp
运行
#include <string>
#include <algorithm>
using namespace std;
string decimalToBase(int num, int base, bool uppercase) {
// 边界处理:num为0
if (num == 0) return "0";
// 校验基数合法性
if (base < 2 || base > 36) return "";
// 字符映射:0-9, A-Z/a-z
const string upperMap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string lowerMap = "0123456789abcdefghijklmnopqrstuvwxyz";
const string& map = uppercase ? upperMap : lowerMap;
string result;
while (num > 0) {
int remainder = num % base;
result += map[remainder]; // 存储低位
num = num / base;
}
reverse(result.begin(), result.end()); // 反转得到高位在前
return result;
}
题目 2:N 进制转十进制(含错误处理与范围检查)
题目描述
实现函数baseToDecimal(const string& str, int base, long long& result),要求:
- 将
base进制字符串str转换为十进制,结果存入result - 支持正负号(如
"-1A"表示负的十六进制数) - 错误处理:返回
bool值,false表示转换失败(如字符超出 base 范围、空字符串) - 范围检查:若结果超出
long long范围,返回false
示例
baseToDecimal("1A", 16, res)→true,res=26baseToDecimal("-101", 2, res)→true,res=-5baseToDecimal("G", 16, res)→false('G' 超出 16 进制范围)
核心难点解析
- 符号处理:先判断首字符是否为 '-',记录符号后从第 1 位开始处理
- 字符合法性校验:对每个字符,转换为数值后需小于
base - 溢出检查:每次计算前判断
result * base + val是否超出long long范围
参考代码
cpp
运行
#include <string>
#include <cctype>
#include <climits>
using namespace std;
bool baseToDecimal(const string& str, int base, long long& result) {
// 空字符串处理
if (str.empty()) return false;
// 基数合法性
if (base < 2 || base > 36) return false;
// 符号处理
int sign = 1;
size_t start = 0;
if (str[0] == '-') {
sign = -1;
start = 1;
if (start >= str.size()) return false; // 仅含负号
}
result = 0;
for (size_t i = start; i < str.size(); ++i) {
char c = str[i];
int val;
// 字符转数值
if (isdigit(c)) {
val = c - '0';
} else if (isalpha(c)) {
c = toupper(c);
val = 10 + (c - 'A');
} else {
return false; // 非法字符
}
// 检查是否超出当前进制范围
if (val >= base) return false;
// 溢出检查:result * base + val 可能超出long long
if (result > LLONG_MAX / base) return false;
result *= base;
if (result > LLONG_MAX - val) return false;
result += val;
}
result *= sign;
return true;
}
三、进阶编程题(小数转换・实战场景)
题目:十进制小数转二进制(精确到指定位数)
题目描述
实现函数decimalFractionToBinary(double num, int precision, string& result),将十进制小数(0≤num<1)转换为二进制小数,要求:
precision为保留的小数位数(如precision=3表示保留 3 位小数)- 若转换过程中提前达到精确值(如 0.5→0.1),则无需补 0
- 处理特殊值:
num=0时输出"0.0"
示例
num=0.625, precision=4→"0.101"(无需补 0,因 0.625=5/8=101/1000₂)num=0.3, precision=4→"0.0100"(0.3≈0.01001100...,取前 4 位)
核心思路
- 整数部分固定为 0(因输入 num<1),先添加 "0." 到结果
- 小数部分处理:循环将小数 ×2,取整数部分(0 或 1)作为当前位,小数更新为乘积的小数部分
- 终止条件:小数部分为 0(精确转换)或达到
precision位数
参考代码
cpp
运行
#include <string>
#include <cmath>
using namespace std;
bool decimalFractionToBinary(double num, int precision, string& result) {
// 输入合法性检查
if (num < 0 || num >= 1 || precision < 1) {
return false;
}
result = "0.";
double fraction = num;
for (int i = 0; i < precision; ++i) {
fraction *= 2;
int intPart = static_cast<int>(fraction); // 取整数部分(0或1)
result += (intPart == 1) ? '1' : '0';
fraction -= intPart; // 更新为新的小数部分
if (fabs(fraction) < 1e-10) { // 小数部分为0,提前结束
break;
}
}
return true;
}
四、工程实践题(综合应用・系统级视角)
题目:IPv4 地址与 32 位整数互转
题目描述
IPv4 地址(如"192.168.1.1")本质是 32 位二进制数,按 8 位分段表示为十进制。实现两个函数:
ipv4ToInt(const string& ipv4, uint32_t& result):将 IPv4 字符串转换为 32 位无符号整数intToIpv4(uint32_t num, string& ipv4):将 32 位整数转换为 IPv4 字符串
示例
ipv4ToInt("192.168.1.1", res)→res=0xC0A80101(即 3232235777)intToIpv4(0x0100007F, ipv4)→ipv4="127.0.0.1"
核心思路
- IPv4 转整数:
- 按
.分割为 4 个十进制数(如192,168,1,1) - 每个数转换为 8 位二进制,拼接后得到 32 位整数(
192<<24 | 168<<16 | 1<<8 | 1)
- 按
- 整数转 IPv4:
- 依次提取 32 位中每 8 位(通过移位和掩码
0xFF),转换为十进制后用.连接
- 依次提取 32 位中每 8 位(通过移位和掩码
参考代码(关键实现)
cpp
运行
#include <string>
#include <sstream>
#include <vector>
using namespace std;
// IPv4转32位整数
bool ipv4ToInt(const string& ipv4, uint32_t& result) {
vector<int> parts;
stringstream ss(ipv4);
string part;
// 分割字符串
while (getline(ss, part, '.')) {
try {
int num = stoi(part);
if (num < 0 || num > 255) return false; // 每个段必须0-255
parts.push_back(num);
} catch (...) {
return false; // 非数字字符
}
}
if (parts.size() != 4) return false; // 必须4个段
// 拼接为32位整数
result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
return true;
}
// 32位整数转IPv4
void intToIpv4(uint32_t num, string& ipv4) {
// 提取每8位
int p1 = (num >> 24) & 0xFF;
int p2 = (num >> 16) & 0xFF;
int p3 = (num >> 8) & 0xFF;
int p4 = num & 0xFF;
stringstream ss;
ss << p1 << "." << p2 << "." << p3 << "." << p4;
ipv4 = ss.str();
}
总结与思维拓展
-
核心方法提炼:
- 十进制→N 进制:整数 "除基取余(逆序)",小数 "乘基取整(顺序)"
- N 进制→十进制:"乘基累加",注意符号和溢出
- 任意进制互转:以十进制为中间桥梁(N→10→M)
-
工程化思考:
- 边界处理:0 值、负数、溢出、非法字符
- 性能优化:大数值转换时避免字符串频繁拼接(可先用 vector<char>缓存)
- 扩展场景:64 位整数、浮点数(IEEE 754 标准)、自定义进制符号集
通过以上训练,不仅能掌握进制转换的代码实现,更能理解计算机中数据的存储本质,为底层编程(如操作系统、嵌入式开发)打下基础。
编辑分享
生成10道高质量C++进制转换题目
提供一份C++进制转换的代码模板
推荐一些讲解进制转换的教学视频
1615

被折叠的 条评论
为什么被折叠?



