数组形参与二进制位运算

数组形参与二进制位运算

题目背景:

输入一个整数,截取它对应的二进制位中从右到左的第8-11位(最右边为第0位)。
**输入格式要求:”%d”
**输出格式要求:”%d “
程序运行示例如下:
2997
1 0 1 1

代码实现:

除2取余(我写的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>

void convert(int num, int digit[]);

int main()
{
int num;
int digit[100];
scanf_s("%d", &num);
convert(num, digit);
for (int i = 11; i >= 8; i--)
{
printf("%d ", digit[i]);
}
return 0;
}

void convert(int num, int digit[])
{
for (int n = 0; num != 0; n++)
{
digit[n] = num % 2;
num = num / 2;
}
}

我第一次将数组作为形参

位运算(哈基米写的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

int main()
{
int num;
scanf("%d", &num);

// 直接从第11位循环到第8位
for (int i = 11; i >= 8; i--)
{
// 核心逻辑:
// 1. (num >> i): 将数字 num 向右移动 i 位,让第 i 位跑到最右边
// 2. & 1 : 取出最右边这一位的值
int bit = (num >> i) & 1;

printf("%d ", bit);
}

return 0;
}

1. 为什么要用 (num >> i) & 1

这是 C 语言里提取某一位数据的黄金公式。我们来看看它是怎么配合工作的。

题目要求:“看看第 i 位是 0 还是 1?”

但是电脑很笨,它通常只能直接看最右边(第 0 位)。如果我们要看中间的某一位,就得把它移到最右边去

  • 步骤解析:

假设我们要看 13 (1101)第 2 位 是什么。

第一步:移位 (num >> 2)

把第 2 位移到最右边的“观察区”。

1 1 0 1 $\xrightarrow{>> 2}$ 0 0 1 1

(原本在第2位的 1,现在跑到了第0位)

第二步:掩码 (& 1)

虽然我们要找的数字已经在最右边了,但它左边还有其他数字(干扰项)。

我们需要用 & 1 (按位与 1) 来“只保留最后一位,把前面全变 0”

  • 0011 (移动后的数)
  • 0001 (这是数字 1)
  • ---- (做 & 运算:两个都是1才是1)
  • 0001 $\rightarrow$ 结果是 1

  • 回到你的题目 (2997)

题目要求截取 2997 的第 11 位到第 8 位。

2997 的二进制是: 1011 1011 0101

当 i = 11 时:

  1. **2997 >> 11**:把第 11 位移到最右边。
    • 移位前:1011 1011 0101 …
    • 移位后:... 0001 (变成了 1)
  2. **& 1**:取出最右边的值 $\rightarrow$ 得到 1

当 i = 10 时:

  1. **2997 >> 10**:把第 10 位移到最右边。
    • 移位前:1011 1011 0101 …
    • 移位后:... 0010 (变成了 2)
  2. **& 1**:...0010 & ...0001 $\rightarrow$ 得到 0
总结
  • >> i:把原本在第 i 位的数字,搬运到最右边(第 0 位)。
  • & 1只看最右边那一位,无视前面所有的数字。

这套组合拳 (n >> i) & 1 就是“把第 i 位搬过来,并把它切下来给你看”

2.十进制2997转化为二进制

当你的代码执行 int num; scanf("%d", &num); 时,内存里发生的事情是这样的:

  1. 输入:你在这个黑框框里打了 2997

  2. 存储:scanf 读到了这几个字符,立刻把它算成数值,然后在内存里划了一块地(4个字节),填入了:

    00000000 00000000 00001011 10110101

    (注:前面的 0 是补齐 32 位的)

关键来了:你的代码并没有“转化”它,只是把它“拿出来看”了。

题目让你取第 11 位到第 8 位。我们来看内存里的这串数:

11 10 9 8 7 6 5 4 3 2 1 0
1 0 1 1 1 0 1 1 0 1 0 1

你的循环做了这 4 件事:

  1. 当 i = 11 时
  • 操作:把那串数字向右移动 11 格 (num >> 11)。
  • 效果:原本在第 11 位的那个 1,现在跑到了最右边(第0位)。
  • 提取:用 & 1 检查,发现是 1。
  • 打印1
  1. 当 i = 10 时
  • 操作:把数字向右移动 10 格 (num >> 10)。
  • 效果:原本在第 10 位的那个 0,跑到了最右边。
  • 提取:用 & 1 检查,发现是 0。
  • 打印0
  1. 当 i = 9 时
  • 操作:右移 9 格。
  • 效果:第 9 位的 1 跑到最右边。
  • 打印1
  1. 当 i = 8 时
  • 操作:右移 8 格。
  • 效果:第 8 位的 1 跑到最右边。
  • 打印1

总结

  • 输入转化:是 scanf 帮你做的,它把人类读得懂的“2997”变成了计算机存得下的“0101…”。
  • 位运算提取:是我们用 >>& 手动做的。我们并不是在计算 2997 怎么变二进制,而是直接去内存里,把已经在里面的那个二进制数的特定几位“抠”出来打印在屏幕上

数组形参与二进制位运算
http://example.com/2025/11/29/数组形参与二进制/
作者
王柏森
发布于
2025年11月29日
许可协议