Lecture 5: Loops and 1D Arrays

Objectives

  • Read and write loops
  • Understand one dimensional arrays
  • Be able to use a loop to traverse an array

Why is looping useful in computation?

A loop is similar to an if statement, in that one needs to decide when to exit the loop (most of the time). Looping is useful for:

  • Being able to process a batch of survey results to do a study
  • Searching through a list of webpages to find the ones that match a keyword
  • Creating a countdown for a timer for a shopping cart
  • Other examples?

Right now, if we want to repeat code, we have to copy and paste it.

public class Countdown {

    public static void main(String[] args) {
      // Set up an initial count value
      int count = 10;

      // Now print and decrease it one by one
      System.out.println(count--);  // "--" acts AFTER we resolve the value, so it prints a 10
      System.out.println(count--);  // it prints a 9
      System.out.println(count--);  // it prints a 8
      System.out.println(count--);  // it prints a 7
      System.out.println(count--);  // it prints a 6
      System.out.println(count--);  // it prints a 5
      System.out.println(count--);  // it prints a 4
      System.out.println(count--);  // it prints a 3
      System.out.println(count--);  // it prints a 2
      System.out.println(count--);  // it prints a 1
      System.out.println("Blastoff!");  
    }
}

The loop above prints out a countdown from 10 down to 1, and then Blastoff!. In addition to using the unary subtraction operator in a potentially confusing way, you can see there is a lot of duplicate code, which, in general, is extremely undesirable.

It turns out, we can use a loop to reduce the duplicate code above while maintaining its functionality.

The while loop

Java has two looping structures, one of them being the while loop. This loop will run while a condition is true; it is just like an if statement, except when you reach the curly block, the computer will jump back up to the conditional check:

public class Countdown {

    public static void main(String[] args) {
      // Set up an initial count value
      int count = 10;

      while (count > 0){
          System.out.println(count--);  // "--" acts AFTER we resolve the value, so it prints a 10 initially
      }

      System.out.println("Blastoff!");  
    }
}

You can immediately see the reduction in code. Let’s run this in the visualizer.

A while loop uses the reserved word while to start, followed by parentheses, like an if statement, for a conditional check.

Class Participation Activity 1 [3 min]

Let’s take a minute or two to modify the loop to count in the other direction.

Note, that one of the most common mistakes people make (myself included!) is forgetting to increment/decrement the counter. Let’s modify the code to do this; you’ll see what’s called an infinite loop, where the loop will go on forever (until you manually hard-exit the program – this is generally bad).

An infinite loop, especially one that doesn’t have a print statement, can look like the computer is “hanging.” If you notice this sort of thing, place a print statement in any while loops you have, and it will immediately become obvious what’s going on.

The for loop

While loops are great, but they’re typically meant to be used when one doesn’t know in advance how many times the loop should be executed – perhaps you want to keep prompting a user to re-enter a password until they pick a valid one:

String password = getPasswordFromForm(); // this is an imaginary method that returns a password from a web form

boolean isValid = check(password); // another imaginary method that checks whether or not the password is valid
while (!isValid){
    System.out.println("Sorry, your password was not valid; please try again.");
    password = askUserToReEnter();
    isValid = check(password);
}

System.out.println("Thank you for entering a valid password!");

Java has an alternative to the while loop for cases when you know in advance how many times you want the loop to execute: the for loop. You can see its elegance for our countdown timer above, where we know in advance exactly how many times we want to run the loop body:

public class Countdown {

    public static void main(String[] args) {
      
      for(int count = 10; count > 0; count--){
          System.out.println(count);  
      }

      System.out.println("Blastoff!");  
    }
}

Here we have moved count inside the loop declaration, where we first initialize it. Then, we have the same conditional check as before, count > 0. And finally, we’ve moved the count-- also into the loop declaration: we will visit this piece of code only after the loop is done (so we don’t need the decrement inside the loop body anymore). Let’s run this code in the visualizer to make sure we understand the three steps above.

Class Participation Activity 2 [5 min]

Change the variable count to be i, which is a common name for index; this is just a normal variable like any other and you can call it whatever you want.

Change the code above in the visualizer to get it to print the numbers 1 through 5 in order, and run it to check your work.

Arrays in Java

Now that we know how to loop, we can dream up some interesting use cases. What if we wanted to go through a list of resumes and see who we want to interview? How can we store these job applicants?

In Java (and other languages) you can store a sequential list of elements in something called an array. It’s basically an ordered list, and best explained with an example:

  public class ArrayExample
  {
    public static void main(String args[])     
    {
       int[] array1 = {2, 4, 5, 22, 3};
       System.out.println(array1.length);
       
       double[] array2 = new double[4];
       array2[0] = 23.2;
       array2[1] = 7.1;
       array2[2] = array2[0];
       array2[3] = 4;

       //array1[0] = 1.5; <--- not allowed, why?
       //array2[4] = 8;   <--- not allowed, why?

       System.out.println(array2.length);
    }
  }

Above, we are storing the ordered list of integers 2, 4, 5, 22, 3 in a variable called array1. You can see the type of this variable is int[], where the brackets are new and indicate this is an array (of integers in this case). In Java an array can only store one type of value which it must declare; above we see both an int[] array and a double[] array.

Note the curly braces around the ordered list in array1. You can also declare an array by only specifying its length; Java will fill up the array with zeroes (if it’s numeric). The syntax is shown above on the third line with the new keyword.

Brackets, with an index, can be used to read and write values, and you can get the size of an array using the length field. Array indices start at index 0. The length of an array is always specified either explicitly or implicitly, as seen above.

Arrays in memory

Let’s run the code above to make sure we understand it.

One of the things you’ll notice is that arrays are not stored on the stack; the array itself is stored in a separate part of memory in Java called the heap. Now it makes sense why we’ve been drawing memory this way all semester; the visualizer does it too. Java uses the heap to store objects where the size can be large (like an array), while the stack is used to store variables (which always fit in a small, known space). In the stack, an array variable stores the memory address to the contents of the array on the heap. Right now, this just seems like extra work, but it will be extremely important for tracing code in Quiz5 and beyond.

Class Participation Activity 3 [3 min]

Modify the code above in the visualizer to declare an array3 that holds the values 3, 11.2, and 4.

Next, declare an empty array with int[] arr = {};

Finally, set array2 = array3; and arr = array1;. What happens in memory?

When assigning any two variables of matching type with =, remember that we always just “copy the box.” This is also true for arrays, as long as we understand that in terms of what an array “stores in the box,” this is not a list of values (even though it looks like it), but is actually a memory address of the start of the entire array.

Consider the following program:

  public class ArrayExample
  {
    public static void main(String args[])     
    {
       int num1 = 4;
       int num2 = 5;
       num1 = num2;
       num2 = 3;
       
       int[] array1 = {2, 4, 5, 22, 3};
       array1[0] = 3;
       array1[1] = array1[1] -7;
       int[] array2 = array1;
       array2[2] = 3333;
       array1[3] = -1000;
    }
  } 

Let’s trace this through in the visualizer first, and then dive deeper on paper to understand what is going on with memory and how arrays are stored.

Note the difference between how primitive types like integer, double, and boolean are all stored on the stack directly (see num1 above). By contrast, complex types like arrays, string, and objects (later) are always stored with a memory address on the stack, while the actual contents are in the heap.

Class Participation Activity 4 [3 min]

What happens when you try to print out your arrays with System.out.println(array1);? Try it out in the visualizer. Now, see what System.out.println(array1 == array2); prints. What do you think is going on?

Arrays and for loops

Now that we understand arrays, we can use for loops to traverse them:

  public class ArrayExample
  {
    public static void main(String args[])     
    {  
        int[] array1 = {2, 4, 5, 22, 3};
      
        for(int i = 0; i < array1.length; i++){
            System.out.println(array1[i]);
        }
    }
  }

Let’s trace this code together in the visualizer.

Class Participation Activity 5 [5 min]

Modify the code above in the visualizer to have it print out the array elements in reverse.

Modify the code above in the visualizer to have it print out every other element.

Next class

We’ll start HW4 to get more practice with loops and arrays.