arrays-and-algorithms Lesson 1 20 min read

Array Basics

Fixed-size, typed collections — your first data structure

Reading: Reges & Stepp: Ch. 7 §7.1

After this lesson, you will be able to:

  • Declare, allocate, and initialize arrays using both new and curly-brace syntax
  • Access elements by index and use .length to determine array size
  • Traverse arrays with standard for loops and enhanced for-each loops
  • Explain why arrays are reference types and what aliasing means
  • Apply array versions of the sum, max, min, and count patterns

The 100-Variable Problem

Suppose you need to store 100 test scores. You could declare 100 variables:

int score1 = 85;
int score2 = 92;
int score3 = 78;
// ... 97 more ...

That is absurd. You cannot loop over 100 separate variable names. You cannot pass them to a method without 100 parameters. And if the number of scores changes, you rewrite everything.

An array solves this: one variable holding multiple values of the same type, accessed by index:

int[] scores = new int[100];
scores[0] = 85;    // first slot
scores[99] = 92;   // last slot

One name, 100 slots. Now you can loop, pass to methods, and handle any size.

From CSCD 110: Python’s lists ([1, 2, 3]) grow dynamically and can hold mixed types. Java arrays are fixed-size and hold only one type. You cannot append to a Java array — its size is set at creation. Java’s ArrayList (covered later this week) is closer to Python lists.


Creating Arrays

Declaration and Allocation

// Two steps:
int[] scores;                // declare (no memory yet)
scores = new int[5];         // allocate 5 slots on the heap

// Or one step:
int[] scores = new int[5];   // declare + allocate

Initialization with Values

int[] scores = {85, 92, 78, 95, 88};

This creates an array of size 5 with those exact values. The curly-brace syntax can only be used at declaration time.

Default Values

When you allocate with new, every slot gets a default:

Type Default
int, long, short, byte 0
double, float 0.0
boolean false
char '\0' (null character)
String and other objects null
int[] data = new int[3];
// data is [0, 0, 0] — not garbage, not undefined

Indexing and .length

Array indices start at 0 and go up to length - 1:

int[] scores = {85, 92, 78, 95, 88};

Index:   [0]  [1]  [2]  [3]  [4]
Value:    85   92   78   95   88

scores.length = 5
scores[0]       // 85 (first element)
scores[4]       // 88 (last element)
scores[5]       // ERROR: ArrayIndexOutOfBoundsException!
scores.length   // 5

Common Pitfall: .length is a property, not a method — no parentheses. Compare: array.length (no parens) vs string.length() (with parens). The last valid index is always array.length - 1.

Check Your Understanding

Given int[] arr = new int[10];, what is the last valid index?


Traversing Arrays

Standard For Loop

Use when you need the index:

int[] scores = {85, 92, 78, 95, 88};

for (int i = 0; i < scores.length; i++) {
    System.out.println("Score " + i + ": " + scores[i]);
}

Enhanced For-Each Loop

Use when you only need the values:

for (int score : scores) {
    System.out.println("Score: " + score);
}

Read as “for each score in scores.”

Key Insight: The for-each loop gives you a copy of each element. Modifying the loop variable does not modify the array:

for (int score : scores) {
    score = 100;  // changes the COPY, not the array!
}
// scores is unchanged!

Use the standard for loop with scores[i] = 100 when you need to modify elements.


Common Array Algorithms

These are the same patterns from Lesson 1.10, now applied to arrays.

Sum and Average

int sum = 0;
for (int score : scores) {
    sum += score;
}
double average = (double) sum / scores.length;

Maximum and Minimum

int max = scores[0];
int min = scores[0];

for (int i = 1; i < scores.length; i++) {
    if (scores[i] > max) { max = scores[i]; }
    if (scores[i] < min) { min = scores[i]; }
}

Starting at scores[0] instead of Integer.MIN_VALUE is cleaner — you compare against an actual element.

Counting Matches

int count = 0;
for (int score : scores) {
    if (score >= 90) {
        count++;
    }
}
System.out.println(count + " scores are A's");

Printing an Array

// DON'T print the array directly:
System.out.println(scores);  // [I@6d06d69c (memory address!)

// DO use Arrays.toString():
import java.util.Arrays;
System.out.println(Arrays.toString(scores));  // [85, 92, 78, 95, 88]
Check Your Understanding

Which loop type should you use to double every element in an array?


Arrays Are Reference Types

This is the most important concept in this lesson. Unlike int or double, an array variable does not hold the data directly — it holds a reference (a pointer) to the data on the heap.

int[] a = {1, 2, 3};
int[] b = a;           // b points to the SAME array!

b[0] = 99;
System.out.println(a[0]);  // 99 — a changed too!

Memory diagram:

Stack                    Heap
┌─────────┐            ┌───┬───┬───┐
│ a: ──────┼──────────►│99 │ 2 │ 3 │
├─────────┤      ┌────►└───┴───┴───┘
│ b: ──────┼──────┘
└─────────┘

Both a and b point to the same array object. This is called aliasing. Changing one changes the other.

This is fundamentally different from primitives:

int x = 5;
int y = x;    // y gets a COPY of x's value
y = 99;
System.out.println(x);  // still 5 — independent copy

Passing Arrays to Methods

When you pass an array to a method, you pass the reference. The method can modify the array’s contents, and the caller sees the changes:

public static void doubleAll(final int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        arr[i] *= 2;
    }
}

int[] data = {1, 2, 3};
doubleAll(data);
System.out.println(Arrays.toString(data));  // [2, 4, 6]

Key Insight: Primitives are passed by value (the method gets a copy). Arrays are also technically passed by value — but the “value” is the reference. So the method gets a copy of the pointer, which still points to the same array. The method cannot reassign the caller’s variable, but it can modify the array’s contents.

Copying an Array

To make an independent copy:

int[] original = {1, 2, 3};

// Manual copy:
int[] copy = new int[original.length];
for (int i = 0; i < original.length; i++) {
    copy[i] = original[i];
}

// Or use Arrays.copyOf():
int[] copy = Arrays.copyOf(original, original.length);

Now copy is independent — changing one does not affect the other.

Check Your Understanding

What does this code print?
int[] a = {10, 20, 30};
int[] b = a;
b[1] = 99;
System.out.println(a[1]);

int[] a = {1, 2, 3};
int[] b = a;
b[0] = 99;
System.out.println(a[0]);

Complete Example: Grade Report

import java.util.Arrays;
import java.util.Scanner;

public class GradeReport {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("How many students? ");
        int n = scanner.nextInt();
        int[] scores = new int[n];

        for (int i = 0; i < scores.length; i++) {
            System.out.print("Score " + (i + 1) + ": ");
            scores[i] = scanner.nextInt();
        }

        // Compute statistics
        int sum = 0;
        int max = scores[0];
        int min = scores[0];
        int countA = 0;

        for (int i = 0; i < scores.length; i++) {
            sum += scores[i];
            if (scores[i] > max) { max = scores[i]; }
            if (scores[i] < min) { min = scores[i]; }
            if (scores[i] >= 90) { countA++; }
        }

        double average = (double) sum / scores.length;

        System.out.println("\n--- Grade Report ---");
        System.out.println("Scores: " + Arrays.toString(scores));
        System.out.printf("Average: %.1f%n", average);
        System.out.println("Highest: " + max);
        System.out.println("Lowest:  " + min);
        System.out.println("A grades: " + countA + " of " + scores.length);
    }
}

Sample run:

How many students? 5
Score 1: 85
Score 2: 92
Score 3: 78
Score 4: 95
Score 5: 88

--- Grade Report ---
Scores: [85, 92, 78, 95, 88]
Average: 87.6
Highest: 95
Lowest:  78
A grades: 2 of 5

Quick Reference

Operation Code
Declare & allocate int[] arr = new int[size];
Declare & initialize int[] arr = {1, 2, 3};
Access element arr[index]
Array size arr.length (no parentheses)
Traverse with index for (int i = 0; i < arr.length; i++)
Traverse values only for (int x : arr)
Print array Arrays.toString(arr)
Copy array Arrays.copyOf(arr, arr.length)

Summary

Arrays store multiple values of the same type in a single variable, accessed by zero-based index. The size is fixed at creation and accessed via .length (no parentheses). Default values are 0, 0.0, false, or null depending on the type.

The standard for loop gives you index access (needed for modification). The for-each loop is cleaner for read-only traversal but gives you copies, not references to elements.

Arrays are reference types. Assigning one array variable to another creates an alias — both point to the same data. Passing an array to a method passes the reference, so the method can modify the original. Use Arrays.copyOf() for independent copies.

Next lesson: Searching arrays — linear search, binary search, and when to use each.