By the end of this lesson, cadets will be able to:
Complete before class. These build the vocabulary we will use.
| Source | Sections | Why |
|---|---|---|
| Beej-C | Chapter 8 cont. (Structs and pointers) | The arrow operator and how structs interact with pointers |
| Beej-C | Chapter 20 (Structs II) | Structs as full citizens: passing them to functions, returning them, and using them with pointers |
p->field) and what it expands tomalloc(N * sizeof(T)) idiommalloc with a freeToday connects three threads you already know. Structs (Lesson 18) gave us a way to bundle related fields. Pointers (Lessons 12 to 16) gave us a way to refer to memory without copying it. malloc and free (Lesson 17) gave us heap allocation. Putting them together yields the workhorse pattern for the rest of CS210 and most of professional C: a dynamically sized array of structs on the heap, with the arrow operator as the everyday notation.
The Lesson 19 deck covers the arrow operator, dynamic arrays of structs, pass-by-pointer mechanics, and the ownership rules when struct members are themselves pointers. The slides are the spine of the in-class lecture; the planets walkthrough is where you practice the mechanics hands on.
When you have a pointer to a struct and you want one of its fields, you have two ways to write it. The long way dereferences the pointer first, then takes the field:
The short way uses the arrow operator. It does exactly the same thing:
In real code you will almost always see the arrow. The parenthesized-deref form is just useful for understanding what the arrow expands to.
Common mistake: writing p.id when p is a pointer. The compiler will reject it with a "member reference base type is not a structure" error. The fix is the arrow.
An array of structs on the heap is the most common dynamic data pattern in C. The shape is always the same:
A few rules of thumb that you will follow in every CS210 lab from here on:
n * sizeof(T), not a hard-coded byte count. If the struct changes size later, your allocation still works.When you pass a struct to a function by value, the function receives a copy. Mutations to its parameter do not affect the caller. This is identical to passing an int by value, except the bytes copied are larger.
To mutate the caller’s struct, take a pointer to it:
Even when the function does not need to mutate, passing by pointer is often the better choice for large structs because it copies only the pointer (8 bytes on a 64-bit system) instead of the whole struct. The convention to signal "I am not going to modify this" is to mark the parameter const:
Suppose a struct has a field that is itself a pointer to heap memory:
Now you have two levels of allocation. The student record itself is one allocation; the name string is another. When you free the student, you have to free both, in the right order:
Order matters. If you free s first, then try to read s->name to free it, you are reading freed memory. The C standard says that is undefined behavior; in practice it sometimes works, sometimes crashes, sometimes leaks. None of those outcomes is acceptable. Free what the struct owns, then free the struct.
The general rule: when you write a struct that owns heap memory through a pointer member, write a paired "create" and "free" function for it. Document who owns what in a header comment. The lab today is built on exactly that pattern.
There is a design idea hiding in everything above. When you wrote the Student struct, you decided which fields belong together. That is decomposition of data: id, gpa, and name are one thing, not three loose variables. When you wrote the roster functions, you decided which operations belong together. That is decomposition of behavior: init, add, remove, print, and free are the things a roster supports.
The skill is doing both at once. When you reach for a struct from now on, design the fields and the functions that operate on them in a single pass. The struct should carry the data the functions need; the functions should know what the struct guarantees. If you find yourself adding a field that no function reads, or writing a function that does not match any struct's responsibilities, the design is drifting. Lesson 6 anchored decomposition for functions; Lesson 19 extends it to data.
Three things to do in class. Use the checklist to track your progress.
Nine tasks across four sections. Type each C statement at the prompt. The terminal shows what the simulator did; the right pane shows the heap and any pointers aimed at it.
Enter your name. It will appear on the completion card so you can include it in your screenshot for the Blackboard reflection.
Planet structs on the heap, fill it with the dot and arrow operators, then free it. The right pane shows the heap as you go.Ten questions. Read each code snippet carefully and trace what main sees. The final score card gives you the completion code to submit on Blackboard.
Enter your name. It will appear on the score card so you can include it in your screenshot for the Blackboard reflection.