CS210 · Block 4 · Lesson 29

Linked Lists I

Self-referential structs · Traversal · Insertion at head and tail
At a glance: Your first dynamic data structure. A linked list is a chain of heap-allocated nodes connected by next pointers — a sequence whose length is unknown until you walk it, and whose front can grow without shifting anything. Today you build chains and insert into them; tomorrow you take them apart.
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. Define a linked list node using a self-referential struct. (Outcome 2)
  2. Traverse a linked list to access or count its elements. (Outcome 2)
  3. Insert new nodes at the head or tail of a linked list. (Outcomes 2, 3)
2. Assigned Readings

Complete before class. There is no Beej chapter for linked lists; the supplementary notes are the spine.

Source Sections Why
Lesson 29 Supplementary Notes All of it (roughly 15 minutes of reading) Self-referential structs, the node concept, traversal idiom, and head/tail insertion mechanics. The vocabulary for the rest of Block 4.
Beej-C Chapter 8 (Structs) revisit Optional. Beej does not cover linked lists directly, but a quick re-skim of struct definitions and the arrow operator helps if those feel rusty from L18-L19.
3. Pre-Class Work
Do this first
About 25 minutes total. Read the supplementary notes carefully, do the warm-up prediction, and confirm your Team PEX test plan is ready to hand in at the start of class.

Pre-Class Checklist

1
Read the Lesson 29 Supplementary Notes
Cover the four sections: the node, the chain, traversal, and insertion. Make sure these terms feel solid:
  • Self-referential struct (struct song { ...; struct song *next; })
  • Heap node lifecycle: malloc → initialize → wire
  • The traversal idiom (while (curr != NULL) { ...; curr = curr->next; })
  • Why head insertion is cheap and tail insertion is not
2
Predict the output
Given the chain head → A → B → C → NULL and this code:
song_t *curr = head;
while (curr != NULL) {
  printf("%s\n", curr->title);
  curr = curr->next;
}
Click for the answer
The loop prints A, then B, then C, each on its own line, then exits when curr becomes NULL. head is never touched — only the local walking pointer moves.
3
Team PEX: test plan check-in is due today
Bring your team's test plan to class. This is the check-in we set up at Lesson 26. Your instructor will collect it during the first few minutes.
4. Lesson Materials and Overview

Up to now your data has lived in arrays and structs of fixed size. A linked list breaks that contract: the data lives in nodes scattered across the heap, connected by pointers. The reference material below covers the four ideas you will see in lecture and use in the listbuild walkthrough.

Jump to
Slides Why Linked Lists The Node Building the Chain Traversal Insertion

Slides

The Lesson 29 deck covers why linked lists exist, the node anatomy, the traversal idiom, and the two insertion patterns. The listbuild walkthrough in Section 5 is where you practice each concept hands-on.

Open Lesson 29 slides →

Why linked lists exist

From CS110 onward you have stored sequences in arrays: contiguous memory, fixed size, indexed access in constant time. Arrays are excellent when you know how many elements you have and the elements rarely shift. Two problems arise when you do not.

Unknown length. When you read a stream of songs from a file or accept names from the user, you do not know how long the sequence is until it ends. Dynamic arrays (L19) handled this by reallocating with a larger buffer and copying, but every reallocation moves the data and invalidates any pointers into the old storage.

Cheap insertion at the front or middle. Inserting at the front of an array of length n requires shifting all n elements one slot to the right. A linked list inserts at the front in three pointer writes regardless of length. The trade is that random access (the equivalent of arr[5]) becomes a walk from the head instead of a constant-time lookup. Whether the trade is worth it depends on the workload.

The node

A node is a struct with two responsibilities: hold one element's data, and hold a pointer to the next node in the chain. The pointer is the same type as the struct itself — self-referential.

typedef struct song {
  char *title;
  struct song *next;  // must say "struct song" here, not "song_t"
} song_t;

The reason the inner self-reference says struct song *next and not song_t *next is sequencing: inside the struct body the typedef name does not exist yet. Once the closing brace and song_t are written, the typedef is in scope everywhere else.

Why a pointer and not the node itself? A node containing another whole node would have infinite size. A node containing a pointer to another node has fixed size — the pointer is just 8 bytes on a 64-bit machine, no matter how long the chain becomes.

Building the chain

Each node lives on the heap, allocated with malloc. After allocation, both fields contain garbage until you set them. The lifecycle is always allocate → initialize all fields → wire into the chain.

song_t *head = malloc(sizeof(song_t));
head->title = "Levitating";
head->next = NULL;  // one-node list ends here

An empty list is the convention head == NULL. Functions that act on lists must handle this case first; reading a field through a NULL pointer is undefined behavior. NULL is also what marks the end of every non-empty chain — the last node's next is always NULL.

Every node you allocate must eventually be freed. We are deferring the safe-cleanup mechanics to Lesson 30; for this lesson, your lab includes a free_list function provided for you. Call it before main returns. The DFCS C Programming Standard, section 8.5, requires that dynamically allocated memory be freed; the rule was introduced at Lesson 15 and is in force for the rest of the course. See the Resources section for the full standard.

Traversal

Visiting every node in the chain uses a walking pointer that starts at the head and steps along the next pointers until it falls off the end. The shape of the loop is identical whether you are printing, counting, summing, or searching.

song_t *curr = head;
// while we haven't fallen off the end:
while (curr != NULL) {
  printf("%s\n", curr->title);
  curr = curr->next;  // step forward
}

Two things to internalize. First, head never moves — only the local curr does. If you walk head instead of a copy, you lose the list. Second, the check happens BEFORE the body, so an empty list (curr == NULL on entry) executes the body zero times — the right behavior.

Insertion

Insertion at the head is three writes and does not depend on the list's length. Allocate the new node, point its next at the current head, then move head.

song_t *new_node = malloc(sizeof(song_t));
new_node->title = "Espresso";
new_node->next = head;  // wire to old front FIRST
head = new_node;      // then move head

The order matters. If you reassign head first, the old chain becomes unreachable — every node after the original head is now an orphan.

Insertion at the tail is more involved because we do not name the last node. To find it, walk from the head until curr->next == NULL; that node is the tail. Then point its next at the new node.

// caller must handle the empty-list case separately
song_t *curr = head;
while (curr->next != NULL) {
  curr = curr->next;
}
curr->next = new_node;
new_node->next = NULL;

Notice the loop condition: curr->next != NULL, not curr != NULL. We want to stop AT the tail, not walk past it. And if the list was empty on entry (head == NULL), this code dereferences NULL on the first line. The caller has to check for empty before calling the traversal, or the function checks first and reassigns head itself. The empty case is half of the work; the lab will surface this.

5. In-Class Work

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

  • Work through the listbuild walkthrough below. Fourteen tasks across four sections covering node anatomy, traversal, and head insertion. About 25 minutes.
  • Take the linked list self-check. Six questions on node definitions, traversal, and insertion order. About 10 minutes.
  • Complete Lab 29: Playlist Builder. Implement node creation, count, head insertion, and tail insertion for a song playlist. Lab 29 on GitHub Classroom →

listbuild Walkthrough

Fourteen tasks across four sections. Build a three-song playlist node by node, walk it with a curr pointer, and insert a new song at the head. The diagram pane shows nodes as boxes with explicit addresses and drawn next-arrows; pointer variables appear above the nodes they target.

Before you begin

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

CS210 Lesson 29 · Linked List Builder

Fourteen tasks across four sections. Build a playlist as a chain of song nodes. The terminal shows what the simulator did; the diagram pane shows the chain, the head pointer, and any walking pointer you create.
Task 0 of 14
Section 1: Node anatomy
Current task
Loading...
Playlist
No nodes yet.
Type the first declaration on the left.
listsim>
How this works: This is not a Linux terminal. It is a teaching tool that simulates a singly-linked list of song nodes. The task card tells you what to type; in walkthrough mode only the expected command advances. Mistype twice and the hint button will pulse. After all tasks are complete, free mode unlocks so you can build, wire, and re-aim chains on your own.

Linked List Self-Check

Six questions covering self-referential structs, the empty-list convention, traversal counting, head-insertion order, and the pass-by-value trap with linked-list functions. Pass at 70% or above; below that, replay the walkthrough and take the quiz again.

Before you begin

Enter your name. It will appear on the score card so you can include it in your screenshot for the Lesson 29 reflection.

CS210 Lesson 29 · Linked List Self-Check

Six questions on node anatomy, traversal, and insertion. Pass at 70% or above; below that, take it again after reviewing.
How this works: One question per card. Pick or type your answer and click Submit. Feedback appears, then click Next to move on. Answers lock once submitted, so think before you submit. After all six, you get a score, a completion code, and a per-question recap.
6. After Class
  • Finish Lab 29 if you did not complete it in class. Submit through GitHub Classroom before Lesson 30.
  • Submit the Lesson 29 reflection in Blackboard. The reflection asks for the listbuild and listcheck completion codes and one short response from the question bank.
  • Read the Lesson 30 supplementary notes. Lesson 30 picks up the same playlist code and adds deletion — including the middle-of-the-list case, where you need the node BEFORE the one being removed.
  • Heads up: Quiz 9 at Lesson 31 covers linked lists (L29, L30, and L31 together).
Need help? Schedule EI with your instructor. Bring the specific code or specific widget screenshots that show the chain you cannot get to behave, and the exact error message or behavior you do not understand. The Resources section has reference materials including the DFCS C Programming Standard if you need to look up a rule. Specific questions get unstuck quickly.