
本文详解在 for 循环内使用 while 循环判断水仙花数(Armstrong 数)时,因错误复用循环变量 s 导致外层 for 陷入无限循环的根本原因,并提供正确、可运行的修复方案。
本文详解在 for 循环内使用 while 循环判断水仙花数(armstrong 数)时,因错误复用循环变量 `s` 导致外层 for 陷入无限循环的根本原因,并提供正确、可运行的修复方案。
在编写判断 1 到 500 范围内水仙花数(即各位数字立方和等于其本身的三位数,如 153 = 1³ + 5³ + 3³)的代码时,一个常见但隐蔽的错误是:在内层 while 循环中直接修改了外层 for 的控制变量 s。这不仅破坏了 for 循环的正常递增逻辑,还导致条件判断失效——最终程序看似“卡住”,实则 for 循环陷入无限执行。
来看原始代码的问题核心:
for(int s = 1; s <= 500; s++) {
int total = 0;
while(s != 0) { // ❌ 错误:用 s 作为被分解的数字,同时又在 while 中修改 s
int digit = s % 10;
total += digit * digit * digit;
s = s / 10; // ⚠️ 此处将 s 不断缩小直至 0 —— 外层 for 的 s 被彻底覆盖!
}
if (total == s) { // ❌ 此时 s 已为 0,条件永远为 false(如 total=153,s=0 → 153==0 → false)
System.out.println(s); // 输出的将是 0,而非原数字
}
}? 问题剖析:
- for 循环变量 s 本应从 1 递增至 500;
- 但进入 while 后,s 被反复执行 s = s / 10(整数除法),最终变为 0;
- while 结束后,for 执行 s++ → s 变为 1;
- 下一轮迭代再次从 s = 1 开始,循环永远无法到达 s > 500 的退出条件,形成无限循环。
✅ 正确解法:引入独立副本变量
应使用一个临时变量(如 temp)保存 s 的初始值,在 while 中操作该副本,而保留 s 用于循环控制和最终比较:
for (int s = 1; s <= 500; s++) {
int temp = s; // ✅ 创建副本,避免污染循环变量
int total = 0;
while (temp != 0) {
int digit = temp % 10;
total += digit * digit * digit; // 立方和(适用于三位数水仙花数)
temp /= 10;
}
if (total == s) { // ✅ 比较的是原始数值 s,而非被修改的 temp
System.out.println(s);
}
}? 输出结果(1–500 内的水仙花数):
1 153 371 407
? 延伸提醒与最佳实践:
- 绝不复用外层循环变量:for/while 的控制变量应在循环体内只读(除非明确设计为手动控制),需提取数字、反转、求和等操作时,务必使用独立变量。
- 注意位数适配:上述代码按“三位数立方和”实现;若要支持任意位数的 Armstrong 数(如 9474 = 9⁴ + 4⁴ + 7⁴ + 4⁴),需先计算数字位数 n,再用 Math.pow(digit, n) 替代固定幂次。
- 边界验证:s=1 是合法水仙花数(1¹ = 1),代码已自然涵盖;s=0 不在范围,无需额外处理。
通过分离数据操作与循环控制职责,即可彻底规避此类“变量劫持”引发的逻辑陷阱——这是嵌套循环调试中最值得警惕的经典反模式。

















