2D Arrays

The goal of this lab period is to practice using 2D arrays in Java. Unlike last week and unlike in most of the other labs you will do this semester, you are not building a Grid class that you will use to store data in your project. This lab is designed to be practice with 2-D arrays that will prepare you for the work in the project, but won't be used directly. You do need to do it to get credit for the lab checkpoint!

What you will build today

One file: Grid.java (one class with a main method)

Checkpoint Requirements (quick checklist)

Important: You will not instantiate a Grid object in this lab. Do not write constructors or getters/setters. Put your work in main (and any needed static helper methods).

+ Common Mistakes (click to expand)


Lab Steps

  1. Step 1 — Setup

    Create a working directory for today's lab/project, then download this Grid.java file and this example README. This is where you will write your code for this lab.

  2. Step 2 — Creating 2D Arrays

    Task A — Declare and allocate a rectangular grid

    In your main method, create a 2D array of type int. In the example below, we'll call it grid (this defines but doesn't instantiate it):

    int[][] grid;

    Allocate the 2D array in a single new statement, giving it 3 rows and 5 columns:

    grid = new int[3][5];

    The first set of square brackets corresponds to the rows, and the second set corresponds to the columns.

    Task B — Allocate a jagged (non-rectangular) grid

    Now try an alternative method: allocate the number of rows first, then allocate each row separately. This lets you create rows with different lengths.

    int[][] grid2 = new int[3][];
    for (int i = 0; i < 3; i++) {
        grid2[i] = new int[i + 1];
    }

    Be a little careful with this method: if you try to access grid2[0][0] before the loop runs, what happens?

    Rectangular vs jagged (visual)
    Rectangular:
    [ ][ ][ ][ ][ ]
    [ ][ ][ ][ ][ ]
    [ ][ ][ ][ ][ ]
    
    Jagged:
    [ ]
    [ ][ ]
    [ ][ ][ ]

    Task C — Fill both grids with random ints

    Fill grid and grid2 by visiting every location with a nested loop and assigning a random integer.

    • Use a nested loop
    • Visit every (row, col)
    • Assign a random int to each location

    + (More Detail)

    When working with 2-D arrays we often use nested for loops:

    for (int i = 0; i < grid.length; i++) {
      for (int j = 0; j < grid[i].length; j++) {
         /* access grid[i][j] */
      }
    }

    This example iterates over all of the elements in the rectangular grid. You will need to generalize this for grid2 or other 2-D arrays by using grid2[i].length for each row.

    Remember: you have to use different names for nested loop variables. For almost all 2-D arrays, loop over rows in the outer loop and columns in the inner loop. Many 2-D arrays are stored in row-major order, so this access pattern tends to be faster.

    While you can hard-code the number of rows and columns into the loops (e.g. 3 and 5), using grid.length and grid[i].length is less error-prone.

    Tip: you can start by assigning a constant value (like 4) to verify your loops work, then replace the constant with a randomly generated integer.

  3. Step 3 — Print the Contents of the 2-D Array

    If you try to print grid directly, what happens? You’ll likely see something like int@somegarbage (a reference). Java arrays don’t implement a “pretty” toString, so you need nested loops to print the contents.

    Print the contents of each 2D array as a 2D grid using nested loops. Make it look nice (the exact formatting is up to you as long as it is clear).

    + (More Detail)

    System.out.print does not add a newline. System.out.println does add a newline. When printing a 2-D array, keep all elements in a row on the same line, then print a newline between rows.

    Example output:

    1 2 7 8 9
    3 4 6 1 2
    2 4 7 6 0

    If you want control over formatting (especially floating point numbers), look at System.out.printf and printf formatting codes.

  4. Step 4 — Concept Shift: References vs Values

    Add the following code to your main method:

    int[][] arr1 = new int[2][2];
    int[][] arr2 = new int[2][2];
    int[][] arr3;
    
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            arr1[i][j] = i + j;
            arr2[i][j] = i + j;
        }
    }
    arr3 = arr1;

    This code generates 3 new 2-D arrays, arr1, arr2, and arr3, all of which contain the same values. This allows you to explore what it means for 2 2-D arrays to be equal in Java.

    Add code below that block that checks (using ==) whether:

    • arr1 is equal to arr2
    • arr1 is equal to arr3
    Important: == tests whether two variables refer to the same object (same reference), not whether two arrays contain the same values.

    Your next task is to write a method named gridEquals that checks whether two 2D arrays contain identical values in the same locations. Your method should have this declaration:

    public static boolean gridEquals(int[][] arr1, int[][] arr2)

    Test that:

    • gridEquals(arr1, arr3) returns true
    • gridEquals(arr1, grid) returns false (where grid is your random rectangular grid)
  5. Step 5 — Adding Command-line Arguments

    The args parameter of main() contains strings from the command line. You can see this by printing the elements of the args array, then running your program a few different times. For example (after compiling Grid.java), try:

    java Grid a b c d

    java Grid hello world command line argument

    Your goal: use two command line arguments to change your program’s behavior. What they do is up to you (surprise us!). Some ideas:

    • Specify the size (rows and/or columns) of the rectangular grid
    • Specify the random range for grid values
    • Create a boolean flag for positive/negative values
    • Pass in actual values instead of random generation

    By this point, your code should already be able to:

    • Create 1 rectangular 2-D array and print its contents
    • Create 1 non-rectangular 2-D array and print its contents
    • Show that gridEquals works on equal and non-equal grids
    • Use 2 command line parameters to affect the program

    Keeping the steps in this exact order is not required — if you’ve been following along, your program should already do all of these things.

  6. Step 6 — Usage Statements

    Many programs require command line arguments to work properly. To be kind to users, you should check for enough arguments and print a usage statement if they are missing.

    + Java example usage output (optional reading)

    Usage: java [options] <mainclass> [args...]
        (to execute a class)
    or  java [options] -jar <jarfile> [args...]
        (to execute a jar file)
    or  java [options] -m <module>/<mainclass> [args...]
    java [options] --module <module>/<mainclass> [args...]
        (to execute the main class in a module)
    or  java [options] <sourcefile> [args]
        (to execute a single source-file program)
    ...

    At the very top of your main method, check whether the user provided at least two command line arguments. If not, print a usage statement and return. If yes, run your program normally.

    Your usage statement does not need to match the Java example above. It should clearly say:

    • How to run your program
    • What the arguments mean
    • Why the user’s input was not acceptable (e.g., missing args)

    Run Grid.java with no arguments, one argument, and with two or more arguments. It should print your usage statement in the first two cases, and run normally in the last case.

  7. Step 7 — Creating a README File

    Usage statements are one way to communicate how to run your program. README files are another. You should include both so that a user can run your program correctly.

    For this lab, your README file should follow these rules:

    • Download the README.txt template from the Google Classroom and add it to your main project folder
    • Follow the instructions in the file.

    Lab checkpoint: Call a lab TA or instructor over and show us your README file. Have us try to run your program (don't tell us anything not in the README). If we're able to run your program correctly, you will get credit for the checkpoint!

  8. Step 8 (Optional) — Transposing a Matrix

    Create a function with the following declaration: public static int[][] transpose(int[][] arr). This function should transpose a rectangular grid.

    Example:

    Original:
    1 2
    3 4
    5 6
    
    Transposed:
    1 3 5
    2 4 6

    You may assume the grid is rectangular (all rows have the same length).

    It is highly recommended that you draw a picture showing where each element moves: original[row][col] goes to transposed[newRow][newCol]. Determine how to compute newRow and newCol from row and col, and how the transposed grid’s size relates to the original.

    At this point, your output should clearly show:

    • Original grid
    • Transposed grid

When you are done with the lab, go ahead and get started on the current project.