高质量 C++ 进制转换专题训练

高质量 C++ 进制转换专题训练(含深度解析)

进制转换是计算机底层数据处理的核心能力,也是 C++ 编程中字符串操作、逻辑运算的典型应用场景。本专题通过分层训练(基础→进阶→工程实践),结合实际开发中的边界情况,帮助学习者构建完整的进制转换知识体系。

一、核心原理巩固(理论 + 手动推演)

题目 1:进制转换数学本质分析

请从 "位权表示法" 角度解释:为什么任意进制数都能转换为十进制?以二进制数101.11和十六进制数3A.5为例,写出其十进制展开式并计算结果。

关键知识点
  • 位权公式:对于基数为b的进制,第i位(整数部分从右往左为 0,1,2...,小数部分从左往右为 - 1,-2...)的位权为b^i
  • 小数转换核心:整数部分 "除基取余",小数部分 "乘基取整"
参考答案
  1. 数学本质:任意进制数均可表示为 "每位数字 × 对应位权" 的总和,而十进制是人类最易理解的中间媒介,因此可通过位权展开实现转换。

  2. 二进制101.11转换:

    • 整数部分:1×2² + 0×2¹ + 1×2⁰ = 4 + 0 + 1 = 5
    • 小数部分:1×2⁻¹ + 1×2⁻² = 0.5 + 0.25 = 0.75
    • 结果:5.75
  3. 十六进制3A.5转换:

    • 整数部分:3×16¹ + 10×16⁰ = 48 + 10 = 58
    • 小数部分:5×16⁻¹ = 5/16 = 0.3125
    • 结果:58.3125

题目 2:特殊值转换边界分析

以下场景在编程中需特别处理,请写出结果并说明理由:

  • 十进制0转换为二进制、八进制、十六进制的结果
  • 二进制11111111(8 位)作为无符号数和有符号数(补码)的十进制值
  • 十六进制0x7FFFFFFF(32 位)加 1 后的十进制结果及溢出原因
参考答案
  1. 0的转换结果均为"0"。理由:0 在任何进制下表示形式唯一,需单独处理避免转换逻辑(如除基取余)因商为 0 而无输出。

  2. 8 位11111111

    • 无符号数:2⁷+...+2⁰=255
    • 有符号数(补码):最高位为符号位(1 表示负),数值部分为~255 + 1 = -1(补码转原码:取反 + 1)
  3. 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进制字符串,uppercasetrue时用大写字母,否则用小写
  • 处理边界:num=0时输出"0"
示例
  • decimalToBase(35, 16, true) → "23"
  • decimalToBase(35, 36, false) → "z"
  • decimalToBase(0, 2, true) → "0"
核心难点解析
  1. 字符映射表设计:需覆盖 0-9、A-Z(或 a-z),可通过 ASCII 码动态生成(如'0' + val for 0-9,'A' + val - 10 for 10+)
  2. 余数存储与反转:因除基取余得到的是低位到高位,需用栈或字符串反转处理
参考代码

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) → trueres=26
  • baseToDecimal("-101", 2, res) → trueres=-5
  • baseToDecimal("G", 16, res) → false('G' 超出 16 进制范围)
核心难点解析
  1. 符号处理:先判断首字符是否为 '-',记录符号后从第 1 位开始处理
  2. 字符合法性校验:对每个字符,转换为数值后需小于base
  3. 溢出检查:每次计算前判断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 位)
核心思路
  1. 整数部分固定为 0(因输入 num<1),先添加 "0." 到结果
  2. 小数部分处理:循环将小数 ×2,取整数部分(0 或 1)作为当前位,小数更新为乘积的小数部分
  3. 终止条件:小数部分为 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 位分段表示为十进制。实现两个函数:

  1. ipv4ToInt(const string& ipv4, uint32_t& result):将 IPv4 字符串转换为 32 位无符号整数
  2. 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"
核心思路
  1. IPv4 转整数:
    • .分割为 4 个十进制数(如192,168,1,1
    • 每个数转换为 8 位二进制,拼接后得到 32 位整数(192<<24 | 168<<16 | 1<<8 | 1
  2. 整数转 IPv4:
    • 依次提取 32 位中每 8 位(通过移位和掩码0xFF),转换为十进制后用.连接
参考代码(关键实现)

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();
}

总结与思维拓展

  1. 核心方法提炼

    • 十进制→N 进制:整数 "除基取余(逆序)",小数 "乘基取整(顺序)"
    • N 进制→十进制:"乘基累加",注意符号和溢出
    • 任意进制互转:以十进制为中间桥梁(N→10→M)
  2. 工程化思考

    • 边界处理:0 值、负数、溢出、非法字符
    • 性能优化:大数值转换时避免字符串频繁拼接(可先用 vector<char>缓存)
    • 扩展场景:64 位整数、浮点数(IEEE 754 标准)、自定义进制符号集

通过以上训练,不仅能掌握进制转换的代码实现,更能理解计算机中数据的存储本质,为底层编程(如操作系统、嵌入式开发)打下基础。

编辑分享

生成10道高质量C++进制转换题目

提供一份C++进制转换的代码模板

推荐一些讲解进制转换的教学视频

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值