数组形参与二进制位运算
数组形参与二进制位运算
题目背景:
输入一个整数,截取它对应的二进制位中从右到左的第8-11位(最右边为第0位)。
**输入格式要求:”%d”
**输出格式要求:”%d “
程序运行示例如下:
2997
1 0 1 1
代码实现:
除2取余(我写的代码)
1 | |
我第一次将数组作为形参
位运算(哈基米写的)
1 | |
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 时:
- **
2997 >> 11**:把第 11 位移到最右边。- 移位前:
1011 1011 0101 … - 移位后:
... 0001(变成了 1)
- 移位前:
- **
& 1**:取出最右边的值 $\rightarrow$ 得到 1
当 i = 10 时:
- **
2997 >> 10**:把第 10 位移到最右边。- 移位前:1
011 1011 0101 … - 移位后:
... 0010(变成了 2)
- 移位前:1
- **
& 1**:...0010 & ...0001$\rightarrow$ 得到 0
总结
>> i:把原本在第i位的数字,搬运到最右边(第 0 位)。& 1:只看最右边那一位,无视前面所有的数字。
这套组合拳 (n >> i) & 1 就是“把第 i 位搬过来,并把它切下来给你看”。
2.十进制2997转化为二进制
当你的代码执行 int num; scanf("%d", &num); 时,内存里发生的事情是这样的:
输入:你在这个黑框框里打了
2997。存储: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 件事:
- 当 i = 11 时
- 操作:把那串数字向右移动 11 格 (
num >> 11)。 - 效果:原本在第 11 位的那个 1,现在跑到了最右边(第0位)。
- 提取:用
& 1检查,发现是 1。 - 打印:
1
- 当 i = 10 时
- 操作:把数字向右移动 10 格 (
num >> 10)。 - 效果:原本在第 10 位的那个 0,跑到了最右边。
- 提取:用
& 1检查,发现是 0。 - 打印:
0
- 当 i = 9 时
- 操作:右移 9 格。
- 效果:第 9 位的 1 跑到最右边。
- 打印:
1
- 当 i = 8 时
- 操作:右移 8 格。
- 效果:第 8 位的 1 跑到最右边。
- 打印:
1
总结
- 输入转化:是
scanf帮你做的,它把人类读得懂的“2997”变成了计算机存得下的“0101…”。 - 位运算提取:是我们用
>>和&手动做的。我们并不是在计算 2997 怎么变二进制,而是直接去内存里,把已经在里面的那个二进制数的特定几位“抠”出来打印在屏幕上。