The exam is in person on Tuesday, December 9, 2025, at 11:00 a.m. America/Los Angeles time in PER 140. You will have 1.5 hours for the exam, or 2.25 hours if you have accommodations. You will take the exam on BrightSpace.
It’s cumulative, but there will be a concentration on material since the last exam, in particular: memory management, systems languages, C, C++, Rust, concurrency, Go, and Pyth.
As with any exam, there is to be no asking for help, no posting on forums, no communication with other humans or intelligent bots in any way. There is to be no signaling of answers (no passing notes around, no speaking, no gesturing). You are bound by an honor code to follow these rules. You’ll be taking the exam online, but electronic assistance will be limited to plain web searches.
Do each of the following to maximize your preparation:
The fact that active recall is better for acquiring long-term knowledge does not mean that outlines and concept maps are not useful. Learners should use multiple techniques—think “both and” rather than “either or.” With that in mind, here is an outline of material covered since the last exam only. To properly review, you must also look at the outlines from the first two exam preparation guides as well.
Memory Management
How basic values are laid out in memory
Alignment and padding
References and pointers
Variable-length data
Slices
Resizable arrays
Linked structures
Implicit referencing and dereferencing
The four memory regions
Code (a.k.a. Text)
Data (a.k.a. Static)
The Stack
What goes in a stack frame
How frames work
Security vulnerabilities
Buffer overflows
Dangling pointers
The Heap
MUCH slower than the stack
Subject to fragmentation
Required for dynamic memory allocation
The horrors of manual memory management
Memory leaks
Dangling pointers
Wild pointers
Double frees
Memory Safety
Preventing memory leaks
Garbage collection
Reference counting
Ownership and Borrowing
Preventing dangling pointers and buffer overflows
Static level checking (no pointers into deeper stack frames)
Disallowance of pointer to stack-allocated data
Disallowance of all explicit pointers
Performance
Can garbage collection be fast?
Calling conventions
Tail recursion
Inlining
Static allocation of leaf functions
Concurrency
Examples of concurrency
From real life
From hardware
From software
Reasons to study
Modeling the real world
Useful, necessary, and inevitable
Superior program structure
Three architectures
Distributed (multi-processing, message passing)
Threads (multi-threaded, within processes, shared memory)
Event-based (just one thread, repeatedly reads queue and services event)
Asynchronicity
The idea of the single-threaded event queue
Callbacks
Promises
Async/Await
Three kinds of agents
Actors (communicate via mailboxes)
Goroutines (communicate via named channels)
Coroutines (share a thread but yield to each other)
Theoretical foundations
Process algebras and calculi exist, but we did not study them
Rich terminology
Program, process, thread
Multiporgramming, multithreading
Concurrency vs parallelism
Concurrency vs Distribution
Deadlock, starvation, livelock, race condition
Safety, liveness, fairness, correctness, fault tolerance
Granularity
Fine-grained vs. coarse-grained
Communication
Message passing
Shared memory
Requires synchronization
Locks
Barriers
Countdown latches
Condition variables
Semaphores
Atomic operations
Monitors
Transactions
Language Patterns
Managed within the language with keywords
Delegated to a library
C
Dennis Ritchie, 1972
CPL -> BCPL -> B -> C
Most recent version, C23, released in 2024
Systems language
Compiles to native machine code (executable)
No VM or runtime
No REPL
No garbage collection, no automatic memory management at all!
Unsafe, but you can do anything and everything
No serious module system, you just source-include ”header” (.h) files
Has a static type system, but it’s easy to subvert
Can get the actual memory address (and size) of a variable
Structs are value types, copied when assigned, passed or returned
Pointers
Explicit
Value is the address of the thing pointed to, or NULL (nullptr in C23 and later)
Can be dereferenced with *
Support addition and subtraction!
&x is the address of, or pointer to, x
*p is the thing pointed to by p
To get the field of a struct that is pointed to, use (*p).x or p->x
Can point to stack allocated variables, but be careful!
Arrays are kind of hybrid between value and reference
Laid out in memory like other value types (stack allocation is ok)
But the value of the array variable is it address
Arrays are not really indexed like you might think
You can’t get the size from a variable (unless it is stack allocated)
NO bounds checking
e1[e2] just abbreviates *(e1 + e2)
so you can write 2[a] in addition to a[2], crazy but true
Strings
Sequence of characters terminated by a null character
Lots of functions in string.h, many are unsafe
Integers
Signed vs. unsigned
Size not strictly defined except for sizeof(char) == 1
However 1 <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
Low-level stuff
Can assign a string of machine code to a function variable and call it
Can cast anything at the bit level by casting to a pointer
C++
Bjarne Stroustrup, 1983
Mostly a superset of C
A C program will almost always run unchanged C++
Compiles to native code, no VM or runtime
No REPL
C++ adds many things to C
Classes, exceptions, and a rich library
stdio.h -> iostream
malloc/free -> new/delete
raw arrays -> std::array, std::vector
char* -> std::string
raw pointers -> smart pointers
Not garbage collected
But you use destructors to make things safer
Also has smart pointers
Still need to know static vs stack vs heap storage as in C
Pointers to locals still allowed
Declarations vs Definitions
Declarators are crazy
& can also be used for aliases
Aliases are confusingly called references
Types
Static but some dynamic checking due to inheritance
Some type inference with auto, but not everything can be inferred
Templates
Classes
Constructors, Destructors, and Assignment operators
Difference between move and copy
Rule of three, Rule of five
=default, =delete
Inheritance
Standard Library
Collections: vector, map, etc.
Strings (char*, std::string)
Functions, function operator, lambdas (require explicit capture)
Rust
Mozilla, 2011-ish
Systems language
Compiles to native machine code
No VM or runtime
Can be used to writing kernels, drivers, etc. (used in Linux, even!)
Frequent winner of most-loved language on Stack Overflow
Known for safety
No memory leaks
No dangling pointers
No data races
Immune from nearly all of the most common memory-based security vulnerabilities
But does have an unsafe mode if needed
Nice type system and many modern features
Type inference
Arrays distinct from slices
No classes and inheritance
Impls and traits instead
Generics
Enums
Pattern matching
Option and Result types
Several pointer types
With an without mut, which is cool
Box, Rc, RefCell, Arc, Mutex, Cell, but we did not cover these
Though str vs String takes some getting used to
Variable immutable by default
Expression-oriented
Very, very few statements
Last expression in block is the value of the block
Which works well for function returns
And for if-else
Ownership and Borrowing
Each value has exactly one owner
Borrowing is a way to pass a reference
Lifetimes (not covered)
Concurrency (not covered)
Cargo - an amazing package manager, and more!
Also builds and runs your code
Also runs your tests
And more
Go
Google, 2009
Yes it IS a garbage-collected language
Known for
Simplicity
Fast compilation
Concurrency
Things it does not have
Classes
"Methods" have a special declaration syntax
Inheritance
Interfaces are way better anyway, according to many folks
Exceptions
Operator overloading
The conditional expression (?:), IKR!
Pointer arithmetic
A "while" keyword - always use "for"
But it does have
Functions as first-class objects
Closures
Multiple function return values
Interfaces
Slices
Maps
Defer statement
Amazing concurrency support
Syntax is rather clean and simple
Very few keywords
Not many symbols (colons and semicolons are rare)
Arrays vs Slices
Arrays are fixed size and by-value
Slices are variable size and by-reference
Most things are pass-by-value (including arrays and structs)
But slices, maps, channels, functions are reference types
Billion Dollar mistake
nil is automatically part of all reference types (SAD)
Why? Designers want pragmatism to outweigh purity and safety here
Pointers
Programmer needs to know when to use them
You can point to stack-allocated variables
But will be moved to the heap automatically if needed!
Concurrency
Goroutines
Like lightweight threads
The is always the main goroutine
Main goroutine finishes when main() finishes
So it is common to make it wait
Waiting can be done with channels or wait groups
Channels
Typed
Read-only, write-only, read-write
Unbuffered (blocking) by default, but can also be buffered (nonblocking)
Select statement
Can wait on multiple channels
Selection is random if multiple channels are ready
Can have a default case if nothing ready immediately
Can have a timeout
Other concurrency features
Mutexes
Wait groups
Atomic operations
Condition variables
As you browse the outlines, make sure you understand each topic by going back over the course notes and the relevant sections in the textbook and associated course readings, where applicable. Remember to not just re-read, cram, and highlight; test yourself with well-crafted, meaningful, and helpful questions. Hopefully you’ve been doing some spaced repetition learning along the way.
It may also be helpful to browse many of the course notes pages on material we did not cover. There is a ton of good stuff there. Sometimes this extra material might expose you to ways in which the basic material you did learn can be used in practice.
Also, as time allows, glance over the course textbook, especially in the intro and summary sections for the languages we covered in class. It is filled with stuff I like to think about, and since I will be writing the final, well, it never hurts to have just a little more comfort with the things I feel are important.
As always, do the recall problems I made available for you in the course notes. But consider writing your own. Write some for each other. You might consider sending selected sections of the course notes into an LLM and have it suggest problems for you, though as always, remember LLMs are very imprecise and make way more mistakes than you might imagine.
There will be a mix of multiple choice, multiselect, matching, short answer, and code fragment writing. The problem order will be randomized for each student. The 23 questions will cover these areas:
Did you know the companion website for the textbook has hundreds of reinforcement problems? Did you know there are some course practice problems from past years. They probably do not align well with the way the course is currently taught, but you might find some of the exercises useful.
As you leave this class, I really hope you’ve become a much better programmer. Please remember:
Go forth and write excellent code. Better than the bots.