CC++ & Algorithm

进制转换——用不同的数字语言说话

中等5
语言版本:C++
概述:学习二进制、八进制、十进制、十六进制之间的转换方法,并了解如何在C++中实现。

用不同进制表达数字——二进制、八进制、十进制、十六进制轻松学

你平时用的数字是十进制,从0到9。但计算机只懂二进制,只有0和1。就像同样一句话,可以用中文、英文、法文来说。不同进制就是不同数字语言。我们来学几种常见进制,学会了就能和计算机“说同一种话”了。

什么是进制?——每个进制有自己的“数字词典”

  • 二进制:基数是2,用到的数字只有 01。计算机内部所有信息都用二进制存储。
  • 八进制:基数是8,数字是 0 ~ 7。(注意:没有8和9)
  • 十进制:基数是10,数字是 0 ~ 9。我们日常用的就是它。
  • 十六进制:基数是16,数字是 0 ~ 9,外加 A ~ F。其中 A 代表10,B 代表11……F 代表15。比如十进制的15,转成十六进制就是 F

? 生活小例子:钟表上用的是六十进制(60秒=1分),而一周用的是七进制(7天=1周)。不同进制就像不同国家的语言,但数字本身的意思是一样的。

怎么把十进制数翻译成其他进制?——短除法倒着取余

方法:不断除以目标进制,记下每次的余数,最后把余数从下往上(也就是倒着)排列。

比如把十进制的 15 转成二进制:

  • 15 ÷ 2 = 7 余 1
  • 7 ÷ 2 = 3 余 1
  • 3 ÷ 2 = 1 余 1
  • 1 ÷ 2 = 0 余 1
    倒着取余数:1111,所以十进制的15等于二进制的 1111

再转成八进制:

  • 15 ÷ 8 = 1 余 7
  • 1 ÷ 8 = 0 余 1
    倒着取:17,所以八进制是 17(读作“一七”,不是十七)。

转成十六进制:

  • 15 ÷ 16 = 0 余 15,15对应 F,所以是 F

小窍门:用短除法时,当商变成0就停止。就像分零食:把一堆糖果按照每袋装几颗分好,剩下的就是余数。

怎么把其他进制数翻译成十进制?——按位权展开相加

每个数字所在的位置都有一个“位权”,从右往左第0位的位权是 进制^0=1,第1位是 进制^1,第2位是 进制^2……然后把每个数字乘以所在位的位权,再相加。

例如:二进制 1010 转十进制:

  • 从右往左:第0位0×2⁰=0,第1位1×2¹=2,第2位0×2²=0,第3位1×2³=8
  • 加起来:0+2+0+8=10,所以 1010₂ = 10₁₀

再比如八进制 17 转十进制:

  • 第0位7×8⁰=7,第1位1×8¹=8,总和=15。

十六进制 F 转十进制:F=15,第0位,所以就是15。

生活例子:就像算零花钱,5张1元(位权1)、3张10元(位权10),加起来就是5+30=35元。

为什么计算机用二进制,程序员爱用十六进制?

  • 计算机用二进制:因为电路只有两种状态:开(1)和关(0),二进制最省事,不容易出错。
  • 程序员用十六进制:因为十六进制可以把一长串二进制写成短的形式。每4位二进制正好对应1位十六进制。比如二进制 1111 就是十六进制的 F,二进制 1010 就是 A。这样写起来既节省空间,又容易看出和二进制的关系。

C++ 自带“翻译机”——直接用库函数转换

C++ 中有现成的工具,我们可以像用翻译 App 一样简单转换。看下面代码:

#include <iostream>
#include <bitset>  // 用于二进制输出
using namespace std;

int main() {
    int n;
    cout << "请输入一个十进制整数: ";
    cin >> n;

    // 输出二进制(用8位表示)
    cout << "二进制: " << bitset<8>(n) << endl;
    // 输出八进制(加上前缀0表示八进制)
    cout << "八进制: " << oct << n << "(前缀0) " << dec << endl;
    // 输出十六进制(加上前缀0x表示十六进制)
    cout << "十六进制: " << hex << n << "(前缀0x) " << dec << endl;

    return 0;
}

运行一下:输入15,输出:

  • 二进制:00001111
  • 八进制:17(前面会自动加前缀0表示八进制数,如017)
  • 十六进制:f(前面有0x表示十六进制,如0xf)

注意:bitset<8> 中的8表示用8位二进制显示,不足的左边补0。如果想显示更多位,可以改成 bitset<16>octhex 是输入输出修饰符,用来告诉 cout 按八进制或十六进制输出;后面的 dec 是改回十进制,不然之后的所有数字都会按八进制输出。

自己动手写一个“手工转换机”——十进制转二进制(循环除2取余)

用库函数很方便,但自己实现更能理解原理。下面代码手动将十进制转成二进制(字符串形式):

#include <iostream>
#include <string>   // 使用字符串
using namespace std;

int main() {
    int n;                          // 输入的十进制数
    cout << "请输入一个十进制整数: ";
    cin >> n;

    string result = "";             // 用来存放二进制结果(字符串)
    int temp = n;                   // 临时变量,避免改变原值
    while (temp > 0) {
        // 取余:余数就是当前最低位的二进制位
        int remainder = temp % 2;   // 余数只能是0或1
        // 把余数转成字符('0'或'1')拼接到结果前面(因为要倒序)
        result = char('0' + remainder) + result;
        temp = temp / 2;            // 继续处理商
    }

    // 如果输入0,结果应该是"0"
    if (result == "") result = "0";

    cout << "二进制: " << result << endl;
    return 0;
}

这段代码用 while 循环反复除2取余,并把余数放到字符串的最前面,这样最后得到的就是正确的二进制(不需要手动倒序)。

试试看:输入 15,输出 1111;输入 0,输出 0。(注意:代码里单独处理了输入0的情况,否则while循环不执行,result为空字符串。)

? 完整可运行示例——一个简单的进制转换器

下面程序让用户输入一个十进制数,然后同时输出二进制、八进制、十六进制(包含库函数和自实现二进制):

#include <iostream>
#include <bitset>   // 库函数二进制输出
#include <string>   // 手动转换需要字符串
using namespace std;

int main() {
    int num;                     // 用户输入的十进制数
    cout << "请输入一个十进制整数: ";
    cin >> num;

    // ---------- 库函数方式 ----------
    cout << "\n【使用库函数】" << endl;
    cout << "二进制(8位): " << bitset<8>(num) << endl;
    cout << "八进制: " << oct << num << "(前缀0) " << dec << endl;
    cout << "十六进制: " << hex << num << "(前缀0x) " << dec << endl;

    // ---------- 手动实现二进制 ----------
    string bin = "";             // 手动计算的二进制结果
    int temp = num;              // 临时变量
    if (temp == 0) {
        bin = "0";               // 输入0的特殊处理
    } else {
        while (temp > 0) {
            int digit = temp % 2;        // 当前位(0或1)
            bin = char('0' + digit) + bin; // 拼到前面
            temp /= 2;                   // 去掉最低位
        }
    }
    cout << "手动计算的二进制: " << bin << endl;

    return 0;
}

如果输入 15,输出效果如下:

请输入一个十进制整数: 15

【使用库函数】
二进制(8位): 00001111
八进制: 17(前缀0)
十六进制: f(前缀0x)

手动计算的二进制: 1111

注意:手动计算的二进制没有前面的0,所以显示为 1111,而库函数 bitset<8> 补足了8位变成 00001111

? 新手最容易犯的3个错误

  1. 余数顺序搞反
    比如转二进制时,把第一个余数放最前面,结果变成 11111111(正确)或者把第一个余数放最后,得到 11111111?不,如果顺序反了,15÷2余1→7÷2余1→3÷2余1→1÷2余1,如果按顺序正着写就是 1111,实际上和倒序一样(巧合)。但换成其他数比如十进制9:9÷2余1→4÷2余0→2÷2余0→1÷2余1,正着写 1001,而正确是倒序得到 1001,呃,其实还是对的?注意:这个例子正序和倒序不同!9÷2第一次余1,最后余1,中间两次余0,如果正着写(从第一次余数到最后一次余数)是 1001,而正确的倒序(从最后一次余数到第一次余数)也是 1001,因为对称。但换一个不对称的数:10(十进制):10÷2余0→5÷2余1→2÷2余0→1÷2余1,正序得到 0101(即101),而正确倒序是 1010(即1010)。明显不同!所以一定要把余数从后往前写。

  2. 十六进制中字母大小写
    C++中输出十六进制时,字母默认是小写(af),但也可以改成大写:用 cout << uppercase << hex << num;。手写转换时,注意1015对应A~F。

  3. 忘记在C++中切换回十进制
    octhex 后,如果不加 dec 恢复,后面所有整数都会按八进制或十六进制输出。例如:

    cout << hex << 15 << " " << 16; // 输出 f 10,因为16在十六进制是10
    

    而加上 dec 后,cout << hex << 15 << dec << " " << 16; 输出 f 16

? 学完这个,接下来可以学什么?

  • 进制之间的快速转换:比如二进制 ↔ 十六进制,每4位二进制一组直接转成一位十六进制。
  • 位运算:在C++中使用 &(与)、|(或)、^(异或)、<<(左移)、>>(右移)对二进制位进行操作,很多算法题会用到。
  • 大数的进制转换:当十进制数很大(超过int范围)时,需要用字符串模拟除法,这在信息学竞赛中很常见。

进制转换是计算机世界的“通用语言”,掌握它,你就更懂计算机的底层逻辑了!

例题精讲

1单选题

将二进制数101101.01转换为十进制数,结果正确的是?

A45.25
B45.5
C45.125
D45.75
2判断题

十六进制数0x1F3转换为十进制数是499。

3填空题
以下C++函数将十进制正整数转换为二进制字符串(无前导零)。请填空。
string decToBin(int n) {
    if (n == 0) return "0";
    string s = "";
    while (n > 0) {
        s = char('0' + n % 2) + s;
        ___;
    }
    return s;
}
4单选题

八进制数73.4转换为十六进制数,结果最接近以下哪个?

A3B.8
B3C.8
C3B.9
D3C.9
5判断题

在C++中,使用std::cout << std::oct << 255 将输出377。(假设已经包含<iomanip>)