- 分享
关于0x3f与0x3f3f3f3f不冲突的问题
- @ 2026-9-24 16:43:59
蒟蒻最近发现前面设 memset(dist, 0x3f, sizeof dist);
与后面判断if (dist[n] == 0x3f3f3f3f)是不冲突。
因为:memset 是按字节填充的,不是按 int 赋值。
写:
memset(dist, 0x3f, sizeof dist);
其中:
0x3f是十六进制数,等于十进制的63,二进制是0011 1111。memset会把dist这块内存的每一个字节都设置成0x3f。- 在常见的 4 字节
int环境下,一个int占 4 个字节,所以它会被填成:
0x3f 0x3f 0x3f 0x3f
也就是:
0x3f3f3f3f
所以执行完:
memset(dist, 0x3f, sizeof dist);
之后,dist 中每个 int 的值实际上就是:
0x3f3f3f3f
因此后面判断:
if (dist[n] == 0x3f3f3f3f);
是完全正确的,不冲突。
可以简单理解为:
memset(dist, 0x3f, sizeof dist);
等价于把每个 int 初始化为:
0x3f3f3f3f
而不是:
0x0000003f
另外,这里用 0x3f3f3f3f 作为无穷大也是常见技巧。因为:
0x3f3f3f3f = 1061109567
两个 0x3f3f3f3f 相加:
0x3f3f3f3f + 0x3f3f3f3f = 0x7e7e7e7e
仍然小于 INT_MAX,不会导致有符号整数溢出。所以它在最短路算法里很适合当 INF。
所以:
memset(dist, 0x3f, sizeof dist);之后,每个int是0x3f3f3f3f。dist[n] == 0x3f3f3f3f判断的是同一个值。- 两者不冲突。
1 comments
-
Myobot @ 2026-9-24 16:44:08
这位同学对
memset的按字节填充机制和0x3f3f3f3f作为INF的优越性理解得很到位,总结基本正确。作为讨论帖,我来做几点补充,帮助大家把这块知识点彻底夯实。一、结论确认
你的核心结论没问题:
memset按字节操作,memset(dist, 0x3f, sizeof dist)会把每个字节写成0x3f;- 4 字节
int上,每个元素被填成0x3f3f3f3f; - 因此
dist[n] == 0x3f3f3f3f与初始化值是同一个数,不冲突。
二、几个值得深挖的点
1. 为什么
memset只能安全地填0x00、0x3f、0xff这类"重复字节"?关键不是"值是多少",而是每个字节是否相同。
- 想填
0:每个字节0x00,可以 →memset(a, 0, ...); - 想填
-1:补码是全1,每个字节0xff,可以 →memset(a, -1, ...); - 想填
0x3f3f3f3f:每个字节0x3f,可以。
反过来,如果你想填
1,memset(a, 1, ...)得到的是0x01010101 = 16843009,而不是1。这是最容易踩的坑,务必记住。2. 关于
0x3f3f3f3f作为INF的"不溢出"论证你的加法推导方向是对的,但表述可以更严谨一点���
- 在 32 位有符号
int下,INT_MAX = 0x7fffffff; 0x3f3f3f3f + 0x3f3f3f3f = 0x7e7e7e7e < 0x7fffffff,确实不会溢出。
但要注意:这只保证"两个
INF相加不溢出"。如果一条边权本身很大,或者路径上做了多次加法(比如 Floyd 里d[i][k] + d[k][j]两端都是INF),结论依然成立,因为INF + INF是上界。而在松弛时通常还会配合if (d[u] == INF) continue;来避免无意义的加法。3. 一个隐藏的坑:判断"不可达"用
==还是>=?在纯 Dijkstra 且不修改
INF值的情况下,dist[n] == 0x3f3f3f3f是安全的。但在 Floyd 或某些实现里,如果
INF参与了加法,dist可能变成0x7e7e7e7e之类的值,此时== 0x3f3f3f3f就会判错。所以更稳妥的写法往往是:if (dist[n] >= 0x3f3f3f3f / 2) // 视为不可达这是一个值得大家养成习惯的写法。
4. 跨平台/类型问题
- 如果
dist是long long,memset(dist, 0x3f, ...)得到的是0x3f3f3f3f3f3f3f3f,此时判断值也要相应改成0x3f3f3f3f3f3f3f3f,不能再用0x3f3f3f3f; - 如果
dist是int数组,但你在64位平台上,int仍是 4 字节,不受指针宽度影响,这点可以放心。
三、留给大家思考的小问题
- 如果我想把数组全部初始化成
-1,memset(a, -1, sizeof a)之后,每个int的十六进制表示是什么?为什么? - 在
long long数组上,INF应该设成什么值,才能保证"两两相加不溢出"?请给出一个十六进制常量。 - 为什么很多模板里
INF用0x3f3f3f3f而不用0x7fffffff?除了"加法不溢出",还有没有别的原因?
把这三个问题想清楚,
memset和INF这块基本就不会再出错了。欢迎继续跟帖讨论。
- 1