CS210 · Block 2 · Lesson 9

Arrays

Contiguous memory · Indexing from 0 · Initialization · Bounds and undefined behavior · The sizeof length idiom
At a glance: Arrays are the first composite data type you meet in C. You already know list-like containers from Python, but C arrays come with two new rules: the size is fixed at declaration time, and there is no built-in bounds checking. The walkthrough in Section 5 lets you watch indices and out-of-bounds accesses physically; the quiz catches the common gotchas; the lab puts it all to work on a pilot-themed analysis problem.
Contents
  1. Lesson Objectives
  2. Assigned Readings
  3. Pre-Class Work
  4. Lesson Materials and Overview
  5. In-Class Work
  6. After Class
1. Lesson Objectives

By the end of this lesson, cadets will be able to:

  1. Declare and initialize arrays of primitive types in C. (Outcome 2)
  2. Access array elements using indexed notation. (Outcome 2)
  3. Identify and avoid common array bugs including off-by-one errors and out-of-bounds access. (Outcome 3)
2. Assigned Readings

Complete before class.

Source Sections Why
Beej-C Chapter 6, sections 6.1 through 6.5 Declaration, initializers, bounds, multidimensional arrays
Stop after section 6.5. Section 6.6 starts the array-pointer relationship, which is Lesson 12 territory. You will not be able to fully follow it until you have seen pointers, and reading it now will only confuse the mental model we are building today.
3. Pre-Class Work
Do this first
Plan on 25 to 35 minutes for the reading. The walkthrough widget in class will reinforce everything, but only if you arrive with the syntax already familiar.

Pre-Class Checklist

1
Read Beej-C Chapter 6, sections 6.1 through 6.5
Section 6.6 starts pointers, which we will cover at Lesson 12. Stop at the end of 6.5. Pay attention to these terms:
  • Array declaration with fixed size
  • Initializer list, including the {0} and designated [i]=v forms
  • Indexing from 0 and the last valid index
  • Out of bounds and undefined behavior
  • The sizeof(a)/sizeof(a[0]) length idiom
2
Skim the In-Class section below
You will see two interactive widgets: an array walkthrough and a self-check quiz. No need to start either yet; just know they are there and what they look like.
4. Lesson Materials and Overview

An array is a fixed-length row of values, all of the same type, stored back-to-back in memory and accessed by integer index starting at 0. Coming from Python, this will feel almost familiar but not quite: the size is fixed, the indices are bounded, and C does no checking. The reference material below covers what you will see in lecture and use in the walkthrough.

Jump to
Slides Python list vs C array Declaring Initializing Indexing Bounds Length Common bugs

Slides

The Lesson 9 deck covers the array model, declaration and initialization, indexing, bounds, the length idiom, and common bugs. The slides are the spine of the in-class lecture; the array walkthrough is where you practice each concept hands-on.

Open Lesson 9 slides →

Python list vs C array

In CS110 you used Python lists: scores = [88, 92, 75, 60, 95]. The list grew when you appended, shrank when you popped, knew its own length via len(scores), and raised an exception if you indexed past the end.

A C array is a different beast wearing similar syntax. It is a fixed-length block of memory carved out at declaration time. It does not know its own length, cannot grow or shrink, and accessing past the end produces undefined behavior rather than an exception.

Behavior Python list C array
Size Grows and shrinks at runtime Fixed at declaration; cannot change
Element type Mixed types allowed All elements must be the same type
Knows its length len(lst) works anywhere sizeof(a)/sizeof(a[0]), declaration scope only
Out of bounds IndexError raised Undefined behavior; no error
Memory layout Implementation-managed Contiguous, predictable

The trade is real. In return for the discipline you get speed, predictable memory layout, and the ability to reason about exactly where each element lives. The cost is that you carry the bounds-checking responsibility yourself.

Declaring an array

An array declaration has three parts: the element type, the array name, and the size in square brackets.

int scores[5];  // five ints, uninitialized at local scope

Three things to remember:

  • The size must be a constant expression known at compile time (a literal, or a #define'd constant).
  • Local (stack) arrays without an initializer contain whatever bytes were in that memory. Do not read them before writing them.
  • Once declared, the size cannot change. There is no append.

Initializing an array

You can initialize an array at the point of declaration using an initializer list in braces.

int scores[5] = {88, 92, 75, 60, 95};

Three variants are worth knowing:

Zero-fill the rest. If the initializer has fewer values than the array length, C zero-fills the remaining cells.

int counts[4] = {0};  // all four cells are 0
int partial[5] = {10, 20};  // 10, 20, 0, 0, 0

Inferred size. If you leave the brackets empty but provide an initializer, C counts the elements for you.

int primes[] = {2, 3, 5, 7, 11};  // length 5, inferred

Designated initializers. You can set specific indices by name. After a designated entry, subsequent values continue from there.

int marks[5] = {[2]=99, 50};  // 0, 0, 99, 50, 0

Indexing

Read or write a single element using square brackets with an integer index. Indices start at 0.

int first = scores[0];  // 88 (the first element)
scores[3] = 100;       // write 100 to the fourth element
The single most important rule for arrays:
For an array of length N, the valid indices are 0 through N-1. The last valid index is always one less than the length.

Out of bounds: C does not stop you

C performs no runtime bounds checking. Reading or writing an out-of-bounds index produces undefined behavior: the C standard says anything is allowed to happen. In practice you might see:

  • A garbage value (whatever bytes were sitting in that memory).
  • A plausible-looking value that is not what you intended.
  • A silent overwrite of another variable nearby in memory.
  • An immediate crash (segmentation fault).
  • A program that appears to work for hours and then fails on different input.
int a[5] = {1, 2, 3, 4, 5};
printf("%d\n", a[5]);  // undefined behavior
a[7] = 42;         // also undefined behavior; worse

Out-of-bounds writes are typically worse than reads. A read returns a bad value but leaves memory intact; a write modifies memory you do not own, potentially corrupting other variables, the call stack, or runtime data. The walkthrough will let you watch this happen.

Computing length: the sizeof idiom

C arrays do not store their length. If you need to know it, you compute it from the total byte size divided by the size of one element.

int scores[5] = {88, 92, 75, 60, 95};
size_t length = sizeof(scores) / sizeof(scores[0]);
// 20 bytes / 4 bytes = 5

Two style notes. First, prefer sizeof(a[0]) over sizeof(int); the first survives a type change without rewriting the expression. Second, this only works in the scope where the array is declared.

Foreshadow:
When you pass an array to a function, the function does not get the size; it gets a memory address (we will see exactly why at Lesson 13). Inside that function the sizeof trick gives the wrong answer. The standard fix, which we will adopt in this lesson's lab, is to pass the length as a separate parameter alongside the array. Watch for this pattern in the function signatures.

Common array bugs

Almost every array bug in your future career is a variation of one of these four. Internalize them now.

Bug What it looks like
Off-by-one in a loop Writing for (i = 0; i <= n; i++) instead of i < n. The last iteration reads or writes a[n], one past the end.
Using length where last index is wanted Asking for "the last element" with a[length] instead of a[length - 1].
Mismatched length parameter Passing a hard-coded count to a function that does not match the actual length of the array you passed.
Reading uninitialized cells Declaring int a[5]; at function scope, then reading a[0] before any write. The compiler does not warn; the value is whatever was on the stack.
5. In-Class Work

Three things to do in class. Use the checklist to track your progress.

  • Work through the array walkthrough below. Nine guided tasks across declarations, indexing, bounds, and the length idiom. About 20 minutes.
  • Take the array rules self-check. Eight questions covering initializer behavior, last valid index, OOB, and the length idiom. 70% to pass. About 10 minutes.
  • Complete Lab 09: Fuel Log Analyzer. Auto-graded through GitHub Classroom. Implement seven array functions against a provided header and main.

Array Walkthrough

Nine tasks across four sections. Type each C statement at the prompt. The terminal shows what happened; the right pane shows the array state with index labels and ghost cells for out-of-bounds accesses.

Before you begin

Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Lesson 9 reflection.

CS210 Lesson 9 · Array Indexing Walkthrough

Watch what an array actually looks like in memory. Read cells. Write cells. See what happens when you go past the edge — because C will let you.
Task 0 of 10
Section 1: Declaration and initialization
Current task
Loading...
Array view
No arrays yet.
Type a declaration on the left.
arr>
How this works: Each array is drawn as a row of cells with index labels above them. Writes flash gold. Reads light up blue. If you read or write past the end of the array, a red dashed ghost cell appears off the side — C does not stop you, but the widget shows you that you stepped off the edge.

Array Rules Self-Check

Eight questions. Some are quick recall; some are subtle gotchas. Answer each one and click Submit. The final card shows your score and a completion code. You need at least 70% (6 out of 8) for a passing code.

Before you begin

Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Lesson 9 reflection.

CS210 Lesson 9 · Array Rules Self-Check

Eight questions covering declaration, initialization, indexing, bounds, and the sizeof length idiom. Answer each one, submit, and move forward.
Heads up: You need at least 70% correct (6 out of 8) to get a passing completion code. Below that, you will get a different code that tells the instructor you did not pass. You can retake the quiz from the score screen.
How this works: One question per card. Pick or type your answer and click Submit. Feedback appears, then click Next. Answers are locked once submitted, so think before you submit. When you finish all eight, you get a score, a recap, and your completion code.
6. After Class
  • Finish Lab 09: Fuel Log Analyzer if you did not complete it in class. Submit through GitHub Classroom before Lesson 10.
  • Complete the Lesson 9 reflection on Blackboard. You will need your two completion codes (one from the walkthrough, one from the quiz) and a screenshot of either completion screen.
  • Read Beej-C Chapter 7 (Strings) for Lesson 10. Strings build directly on what you learned today: they are arrays of char with one extra rule.
  • Replay the walkthrough in free mode. Try declaring two arrays with the same name, an array of length 1, an index of -1. See what the widget tells you.
  • Heads up: Quiz 3 at Lesson 10 covers arrays and strings together.
Need help? Schedule EI with your instructor. Bring specific code or specific screenshots, and the exact error or output you do not understand. Specific questions get unstuck quickly.