CMSI 3801
Final Exam Preparation

When and How

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.

Scope

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.

Ground Rules

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.

Preparation Checklist

Do each of the following to maximize your preparation:

An Outline of Course Content

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

Other Ways to Review

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.

About the Problems

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:

More Practice!

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.

One Last Thing

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.