Ugh! Bugs. They’re always crawling around and flying in your face when you least expect. The same applied to computer science bugs. They’ve been around since 1947 with the early computers, and continue to annoy us today. The first recorded case of a bug was a moth that Grace Hopper found jamming a relay switch in September 1947 (http://www.computerhistory.org/tdih/september/9/). While not much could be done about moths flying into relay switches except climbing in and pulling them out, today we can debug without having to leave our chairs.
So, let’s get started.
An Ounce of Prevention
The best way to avoid bugs is taking steps to ensure they don’t occur in the first place. Most of these are common sense like sensibly naming variables, maintaining consistent indentation and bracketing style, determining loop conditions before programming a loop, and remembering that arrays index at 0. Commenting a tricky bit of code can also help when you come back to it later.
First, let’s look at some code that could use a bit of prevention:
public class BadCode { public static void main(String[] args) { // TODO Auto-generated method stub /* prints out the squares of integers from 1 to 20 inclusive * */for(int i = 0; i < 20; i--) { System.out.print("%4d", Math.pow(i, i))) } // make an array and fill it with the sqrts of non-negative numbers through 20 exclusive int [] sqrts = {}; for (int j = 1; j <= 20; j++) { sqrts[j] = Math.sqrt(j) } // print out the array for (int i = 0; i > 20; i++); System.out.println(sqrts[]); } }; } }
This code is clearly messed up: the closing curly brackets don’t align, there are semi-colons in the wrong places and missing from the right ones, etc. At this point it won’t compile. It also has some logic errors. Try debugging it yourself, then click below to see our fixed-up version. (Hint: there are # bugs).
A Pound of Cure
Sometimes we let our code get messy. It’s just part of the process of programming. In that case, we need ways to fix it when things go wrong. The old foolproof way of programming is scattering print statements like salt. We’ll look at doing this first. Then we’ll explore a couple of other tactics.
import java.util.Scanner; public class PrintSaltScatter { public static void main (String [] args) { // Read in a list of points and store them in an array. // The first number read in will be the count Scanner in = new Scanner(System.in); int count = in.nextInt(); int [] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = in.nextInt(); } // print out the array for (int i = 1; i < count- 1; i++) { System.out.print(array[i] + ", "); } // print out the array with each element divided by 2 for (int i = 0; i < count; i++) { int j = array[i/2]; System.out.print(j+ ", "); } } }
Right now, the code compiles and runs, but it hangs at first waiting for user input. It’s output also looks a bit wonky:
5 1 2 3 4 5 2, 3, 4, 1, 1, 2, 2, 3,
To make it easier to understand what’s happening during the development process, we should make it more clear what we want. We can do this by adding lines that say “Please enter how many integers you will input:” before we read in count, and “Please enter an integer: ” before we read in each number. Now the code looks like this
import java.util.Scanner; public class PrintSaltScatter { public static void main (String [] args) { // Read in a list of points and store them in an array. // The first number read in will be the count Scanner in = new Scanner(System.in); System.out.println("Please enter how many integers you will input: "); int count = in.nextInt(); int [] array = new int[count]; for (int i = 0; i < count; i++) { System.out.println("Enter an integer: "); array[i] = in.nextInt(); } // print out the array for (int i = 1; i < count- 1; i++) { System.out.print(array[i] + ", "); } // print out the array with each element divided by 2 for (int i = 0; i < count; i++) { int j = array[i/2]; System.out.print(j+ ", "); } } }
and the output looks like this:
Please enter how many integers you will input: 5 Enter an integer: 1 Enter an integer: 2 Enter an integer: 3 Enter an integer: 4 Enter an integer: 5 2, 3, 4, 1, 1, 2, 2, 3,
We can now see we entered 5 integers and that the printout is doing something weird because we’re getting only eight numbers when we should get 10.
Let’s add a print statement to line 21 to see what’s happening:
System.out.println("i: " + i);
Now it’s printing out the index after what is stored in the index.
Enter an integer: 5 2, i: 1 3, i: 2 4, i: 3 1, 1, 2, 2, 3,
Aha! We’re indexing from 1 to 3. Now we’re also seeing things print on a new line. Let’s add another 2 statements to determine if the issue is the second or third loop.
import java.util.Scanner; public class PrintSaltScatter { public static void main (String [] args) { // Read in a list of points and store them in an array. // The first number read in will be the count Scanner in = new Scanner(System.in); System.out.println("Please enter how many integers you will input: "); int count = in.nextInt(); int [] array = new int[count]; for (int i = 0; i < count; i++) { System.out.println("Enter an integer: "); array[i] = in.nextInt(); } // print out the array System.out.println("You entered: "); for (int i = 1; i < count- 1; i++) { System.out.print(array[i] + ", "); System.out.println("i: " + i); } // print out the array with each element divided by 2 System.out.println("Here are the numbers, each divided by 2: "); for (int i = 0; i < count; i++) { int j = array[i/2]; System.out.print(j+ ", "); } } }
Output:
Enter an integer: 5 You entered: 2, i: 1 3, i: 2 4, i: 3 Here are the numbers, each divided by 2: 1, 1, 2, 2, 3,
We can see two problems here now quite clearly: the second loop only visits indices 1, 2, and 3, and the last loop is not in fact dividing things by two. We fix the counter variable and condition in the second loop. Then we change array[i/2] to array[i] / 2.
import java.util.Scanner; public class PrintSaltScatter { public static void main (String [] args) { // Read in a list of points and store them in an array. // The first number read in will be the count Scanner in = new Scanner(System.in); System.out.println("Please enter how many integers you will input: "); int count = in.nextInt(); int [] array = new int[count]; for (int i = 0; i < count; i++) { System.out.println("Enter an integer: "); array[i] = in.nextInt(); } // print out the array System.out.println("You entered: "); for (int i = 0; i < count; i++) { System.out.print(array[i] + ", "); System.out.println("i: " + i); } // print out the array with each element divided by 2 System.out.println("Here are the numbers, each divided by 2: "); for (int i = 0; i < count; i++) { int j = array[i] / 2; System.out.print(j+ ", "); } } }
It still isn’t giving us quite what we want, although the second loop is now working:
Enter an integer: 5 You entered: 1, i: 0 2, i: 1 3, i: 2 4, i: 3 5, i: 4 Here are the numbers, each divided by 2: 0, 1, 1, 2, 2,
Our final problem is Integer Division, which means we need to change j to a double and either cast 2 to a double or write it as 2.0. With this changed, things now work as expected, and the program has been debugged.
import java.util.Scanner; public class PrintSaltScatter { public static void main (String [] args) { // Read in a list of points and store them in an array. // The first number read in will be the count Scanner in = new Scanner(System.in); System.out.println("Please enter how many integers you will input: "); int count = in.nextInt(); int [] array = new int[count]; for (int i = 0; i < count; i++) { System.out.println("Enter an integer: "); array[i] = in.nextInt(); } // print out the array System.out.println("You entered: "); for (int i = 0; i < count; i++) { System.out.print(array[i] + ", "); System.out.println("i: " + i); } // print out the array with each element divided by 2 System.out.println("Here are the numbers, each divided by 2: "); for (int i = 0; i < count; i++) { double j = array[i] / (double) 2; System.out.print(j+ ", "); } } }
The output is below:
Please enter how many integers you will input: 5 Enter an integer: 1 Enter an integer: 2 Enter an integer: 3 Enter an integer: 4 Enter an integer: 5 You entered: 1, i: 0 2, i: 1 3, i: 2 4, i: 3 5, i: 4 Here are the numbers, each divided by 2: 0.5, 1.0, 1.5, 2.0, 2.5,
Here’s the original BadCode and the final Debugged version so you can try out debugging on your own.