By the end of this lesson, cadets will be able to:
Complete before class. There is no Beej chapter for this lesson; the instructor notes are the source and they are short.
| Source | Sections | Why |
|---|---|---|
| Lesson 33 supplementary notes (instructor-written) | All of it | The two axes, stack overflow, and when recursion wins. This is the reading. |
| Lesson 32 notes and widget | The deferred-operation model | Optional review. Today builds directly on every suspended frame holding a deferred operation. |
num + ?, while it waited for the call beneath it. Today that picture explains the cost: every deferred frame is real memory on the stack. If that idea is fuzzy, replay the Lesson 32 widget.By now you can write a traversal either way. This lesson is about choosing. The reference material below is the spine of the in-class discussion; the widget is where you see the two axes pull against each other on real code.
The Lesson 33 deck walks through the two axes, the stack-cost picture, the overflow demo, the case where recursion wins, and how to decide. The slides are the spine of the in-class discussion; the widget is where you practice the judgment hands-on.
Take any traversal you wrote recursively in Lesson 32 and you can write it as a loop instead. Both return the same answer, so correctness does not separate them. Two things do. The first is clarity: how easily the next reader can see the code is correct. The second is cost: what the code consumes on the call stack while it runs. Every recursion-vs-iteration choice is a weighing of these two.
For a function like total time, clarity is close to a tie. The recursive version reads as "this split plus the total of the rest," which mirrors how a list is defined; the loop is an ordinary accumulator that any C programmer reads at a glance. When clarity ties, cost decides.
The iterative version keeps one stack frame and updates its variables in place, no matter how long the list. That is O(1) space on the stack. The recursive version adds a frame per element, because each call must call again before it can finish, and none of those frames can be freed until the base case at the bottom. That is O(N) space on the stack. Each of those frames holds a deferred operation, exactly the Lesson 32 picture, and each one is real memory.
The call stack is a fixed region, often around 8 megabytes. As long as all live frames fit, you are fine. When they do not, the program crashes; that is a stack overflow, and in C it usually shows up as a segmentation fault before your function can return anything. A recursive forward walk over a few hundred thousand nodes will exhaust the stack and crash. The iterative version walks the same list in one frame and returns the right answer. This is the main practical reason to prefer iteration for traversals that could run long; it is not that the recursive code was worse to read.
A note for the curious: a "tail call," where the recursive call is the last thing the function does, can sometimes be optimized into a loop. C does not guarantee this, and an accumulating function like total time is not in that shape anyway. Treat deep recursion in C as a real overflow risk.
If cost were the whole story you would always loop. It is not. Consider printing a list in reverse, tail first. A singly linked list has no pointer back toward the head, so a single forward loop physically cannot reach the tail first. To print in reverse with a loop you would make two passes or build your own stack of pointers. Recursion gets it almost for free:
The recursive call comes before the print, so every frame descends to the tail before anything prints, and the deferred prints fire in reverse as the stack unwinds. The call stack does the bookkeeping you would otherwise build by hand. This is the honest case for recursion, and it is the same reason free_list and collect_reverse recursed in Lesson 32.
So the decision is never "recursion good" or "recursion bad." For a plain forward walk that might run long (length, sum, search, total), clarity ties and stack cost breaks it toward iteration: write the loop. For work the structure forces to happen tail first, recursion is clearer and more practical: write the recursion. And the cost axis only bites when the input can actually get large; a recursive function over a guaranteed small, bounded input is a perfectly defensible choice, because there clarity gets to decide on its own.
A useful habit when unsure: ask how long the input can get and whether the recursion stacks a frame per element. If the input is unbounded and the answer is yes, that is your signal to write the loop.
No new section of the DFCS C Programming Standard is introduced today. Because these functions are short, the inline-comment guidance (§2.4) applies lightly: a comment explaining why print_reverse recurses before printing earns its place; a comment restating what an obvious loop does not. Keep naming and formatting consistent with what the tooling has enforced since Lesson 7.
Two things to do in class. Use the checklist to track your progress.
Five tasks. Pick a function and a list length, run both versions, and weigh clarity against cost. The last task is a judgment call, not a demo.
Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Blackboard reflection quiz.