7.2 - Arrays (2026-10-09)
Watch on YouTube →
Overview
Chris Bourke explains C arrays by contrasting fixed-size stack arrays with dynamically allocated heap arrays, then demonstrates how to allocate, use, and release memory safely. He shows why C programs must track array lengths explicitly, how to pass arrays to functions, and how `const` prevents unintended changes; the lecture ends with a deliberately buggy sum function for the next class.
Key takeaways
- A five-element C array has valid indices 0–4; accessing an index outside that range is undefined behavior, not a bounds-checked error.
- Dynamic allocation moves array storage to the heap, but the pointer must be checked for `NULL` and the allocation must eventually be released with `free`.
- Repeatedly allocating 40 MB without freeing it creates a memory leak that can exhaust system resources; freeing each allocation keeps the process's memory use from continually growing.
- C does not reliably store a dynamic array's length with its pointer, so callers must maintain and pass the element count explicitly.
- Array pointers let functions modify the caller's data; declaring elements `const` communicates read-only intent and lets the compiler catch accidental writes.
- Testing null, empty, single-element, and ordinary arrays exposes different boundary conditions, including mistakes in comma formatting and index calculations.
Chapters
0:00
Course Reminders and the Shift to C Arrays
- Chris Bourke reminds students to schedule Exam 2 at the Digital Learning Commons.
- He previews computing-course registration information and introduces the lecture's focus on static and dynamic arrays in C.
4:00
Static Stack Arrays Versus Dynamic Heap Arrays
- A declaration such as `int ar[5]` creates five integers in the stack frame; valid indices run from 0 through 4.
- A dynamic array uses an integer pointer and `malloc(5 * sizeof(int))` to request space on the heap.
- The stack is comparatively limited—Bourke cites about 8 MB—while heap allocations can be much larger, subject to available memory.
8:00
Allocating Memory, Handling Failure, and Staying in Bounds
- `sizeof(int)` makes allocation portable across systems where an integer's byte size may differ; a cast assigns the returned address to the intended pointer type.
- `calloc` also zeroes allocated memory, while `realloc` attempts to resize an existing allocation and can fail.
- Allocation functions can return `NULL`; code must not use the pointer if the request fails.
- Writing to `ar[2000]` when only five elements were allocated produces undefined behavior and may cause a segmentation fault.
12:00
Why `free` Prevents Memory Leaks
- Bourke compares allocated memory to a library book: call `free(array)` once the program is finished using it.
- A loop that repeatedly allocates 40 MB without freeing it consumes memory rapidly; the operating system eventually kills the runaway process.
- Freeing each allocation before the next iteration keeps memory use roughly steady, rather than growing without bound.
21:00
Use-After-Free, Double-Free, and Invalid Pointers
- After `free`, the program no longer owns the memory; reading it can return corrupted values or trigger a segmentation fault.
- Calling `free` twice on the same pointer can cause a double-free error or crash.
- Passing a pointer to a stack variable, such as `&x`, to `free` is invalid and can trigger compiler warnings or an abort.
- Bourke stresses that these memory errors are undefined behavior and can create security vulnerabilities when they do not fail visibly.
27:40
Dynamic Arrays Require Explicit Size Bookkeeping
- C provides no reliable runtime way to recover the length of a dynamically allocated array from its pointer.
- The programmer must store the element count separately and pass it alongside the pointer to every function that needs the array.
- Bourke warns that apparent array-length techniques found online often apply only to static arrays or compiler-specific tricks.
31:24
Building `print_array` with a Pointer and Length
- Bourke fills a 10-element integer array with multiples of 10 and writes a formatted printer that produces bracketed output without a trailing comma.
- The function accepts an array pointer plus `n`, the number of elements, because the pointer alone does not encode the length.
- The implementation handles a null pointer separately and treats a size of zero or less as an empty array.
- Passing an incorrect size, such as 100 for a 10-element allocation, makes the function read beyond the array and print garbage or invoke undefined behavior.
36:00
Testing Array Edge Cases and Protecting Data with `const`
- Bourke traces the one-element case: the loop that prints comma-separated elements does not run, and the final-element step prints the sole value correctly.
- He recommends testing null, empty, single-element, and multi-element arrays, ideally with unit tests rather than only ad hoc checks.
- Because a pointer gives a function access to the original array, a printer could accidentally overwrite its contents.
- Declaring the pointer's elements `const` in both the prototype and definition lets the compiler reject unintended writes.
43:33
Array-Function Review and the Next Class's Buggy Sum
- Bourke summarizes the function interface: pass an array pointer and its size, and use `const` when the function should only read the elements.
- He begins a `sum` function that should compute the total of an integer array and return an integer.
- The example is intentionally left with at least three problems for the next Monday session; Bourke specifically flags the return-type declaration as incorrect.
Summary, takeaways, and chapters were generated by AI from the video's transcript and may contain errors. The video belongs to its creator, Chris Bourke.