写在前面的废话
lab2 的难度不是很高,其主要设计思路就是帮助学生熟悉 Intellj IEDA
中 debugger
工具的使用。但是其中涉及了一些 Java
的语法,对 Java
小白不是很友好。再就是上一篇blog里我说要持续更新 CS61B
的 lab
和 proj
,所以这部分虽然不难,但还是写了这篇blog。
lab2
预计用时 1 ~ 3 小时(比proj0
少多了 😦 )
如果以前接触过别的 debugger
,这里大部分内容对你来说都会比较简单。
one more times : 本人小白,希望路过的大佬手下留情
前言
这次的 lab2
要求我们找到三个密码来解除一个 “炸弹”💣 ,密码会在程序运行的时候产生,所以我们要用 debugger
来监视程序运行时变量的 value
。
三段代码一次呈现
先看代码,解释在后面
public class BombMain {
public static void main(String[] args) {
int phase = 2;
if (args.length > 0) {
phase = Integer.parseInt(args[0]);
}
// TODO: Find the correct inputs (passwords) to each phase using debugging techniques
//原文的部分注释给删掉了
Bomb b = new Bomb();
if (phase >= 0) {
b.phase0("39291226");
}
if (phase >= 1) {
b.phase1(IntList.of(0,9,3,0,8));
}
if (phase >= 2) {
int i = 0;
String a = "A ";
while (i < 1336){
a =a + "A ";
i++;
} //这里的奇怪循环后面会解释
a = a + "-81201430";
b.phase2(a);
}
}
}
Bomb Introduction (Phase 0)
这是 Bomb.java
文件中关于 Phase 0
的代码
public void phase0(String password) {
String correctPassword = shufflePassword("hello");
if (!password.equals(correctPassword)) {
System.out.println("Phase 0 went BOOM!");
System.exit(1);
}
System.err.println("You passed phase 0 with the password \"" + password + "\"");
}
这里出现了一个 password.equals()
的函数,这不是我们自己写的函数,而是一个库函数。需要强调,我们要学会自己查找库函数或者 Java
的标准语法,这里提供一个官方网址Java SE 21
上文函数的具体内容public boolean equals(Object anObject)
实际上,获取这个密码并不需要详细了解这个函数的功能,按如下方式设置断点,然后 “步过” 一次,可以看到我们的 passwors
和正确密码 correctPassword
都显示了出来。
灰色波浪线的部分表示 这部分程序不会执行 (因为 if
条件为 false
)
其实正常是在这里查看相关的变量的值,但是 Intellj IDEA
贴心的在相应的行上显示的相关值。
所以 password
就是 "39291226"
啦,填入到 BombMain.java
文件中就好啦
Visualizer (Phase 1)
这里强调让我们学习使用 Visualizer
就是这个
上图是 password
正确的时候 Java Visualizer
的显示
如果不改动开始时的代码
if (phase >= 1) {
b.phase1(null); // Figure this out too
}
Java Visualizer
的显示是这样(在 Bomb.java
文件的46行处打断点)
注意到 corrrectIntListPassword
指向了一个链表,我们需要让我们的 password
和这个链表相同,根据课程文档的提示,我们使用 IntList.of()
函数
/**
* Method to create an IntList from an argument list.
* You don't have to understand this code. We have it here
* because it's convenient with testing. It's used like this:
* <p>
* IntList myList = IntList.of(1, 2, 3, 4, 5);
* will create an IntList 1 -> 2 -> 3 -> 4 -> 5 -> null.
* <p>
* You can pass in any number of arguments to IntList.of and it will work:
* IntList mySmallerList = IntList.of(1, 4, 9);
*/
public static IntList of(int... argList) {
if (argList.length == 0)
return null;
int[] restList = new int[argList.length - 1];
System.arraycopy(argList, 1, restList, 0, argList.length - 1);
return new IntList(argList[0], IntList.of(restList));
}
我们不需要完全明白这个函数的原理,只需要知道它可以创建一个链表即可。所以我们的 password
为
if (phase >= 1) {
b.phase1(IntList.of(0,9,3,0,8));
}
Conditional Breakpoints (Phase 2)
这部分希望我们学会对断点进一步设置以便于 debug
。其难点在于需要自己弄明白一点课外的 Java
语法
首先是
public String[] split(String regex)
然后是public static int parseInt(String s)
还有for (int item : array){}
(这三个是连接,可以直接跳转)
public void phase2(String password) {
String[] passwordPieces = password.split(" "); //对应这里
Random r = new Random(1337);
Set<Integer> numbers = new HashSet<>();
while (numbers.size() < 100000) {
numbers.add(r.nextInt());
}
boolean correct = false;
int i = 0;
for (int number : numbers) { //这里
if (i == 1337 && Integer.parseInt(passwordPieces[i]) == number) { //和这里
correct = true;
}
i++;
}
if (!correct) {
System.out.println("Phase 2 went BOOM!");
System.exit(3);
}
System.err.println("You passed phase 2 with the password \"" + password + "\"");
}
我们在检测密码的地方打断点( Bomb.java
文件的67行)结果如图
如果你操作正常,你的运行结果和上图应该是不一样的 😃
有两个原因
- 没有对断点进一步设置
password
不一样
断点可以这样设置
因为 if()
的第一个条件是 i == 1337
所以我们可以直接去到 i == 1337
的时候
**此时如果你已经明白上面提到的 三个函数 (这个连接不是很好用 😐 )你应该会意识到字符串数组 passwordPieces
的第1338个元素应该是 -81201430
我们的密码要有1337个空格,前1337项不重要,让第1338项为 -81201430
即可。
所以有如下代码
if (phase >= 2) {
int i = 0;
String a = "A ";
while (i < 1336){
a =a + "A ";
i++;
}
a = a + "-81201430";
b.phase2(a);
}
//这里 a = "A A A A A ... A A A -81201430" 'A'共1337个,没有实际含义,仅用于占位
课程文档给了这样一个提示
因此我认为我的思路是正确的 😃 离谱
结尾
到这里 lab2
就完成了,看一眼运行结果吧
(”A ……“ 很长,不截了)
以后还会继续更新,欢迎同在自学 CS61B
小伙伴一起交流,也欢迎路过的大佬指点。
彻底结尾了,感谢阅读!!