liveBook · Manning

Recursion

As explained in Modern C, Third Edition

Recursion is a technique in which a computation is defined or performed by calls to the same computation on smaller or simpler inputs.

Consider `gcd2(18, 30)`. It calls `gcd2(12, 18)`, then `gcd2(6, 12)`, then `gcd2(0, 6)`, which returns 6. A function that calls itself, directly or indirectly, is recursive. Every active call has its own parameters and local variables; an earlier call remains active while a later one runs. section 7.3

inline size_t gcd2(size_t a, size_t b) [[__unsequenced__]] {  1 
  assert(a <= b);               2  
  if (!a) return b;    3  
  size_t r = b % a;            4  
  return gcd2(r, a);     
}

The `gcd2` listing shows both essential parts: `if (!a) return b` stops the calls, and `gcd2(b % a, a)` advances toward that case. For positive `a`, the remainder is smaller than `a`. The assertion requires the ordered inputs this helper expects; the separate `gcd` wrapper checks for positive inputs and orders them. section 7.3

TAKEAWAY: Identify a stopping condition and show that every recursive step makes progress toward it. Without both, calls can continue until call resources are exhausted. A compiler can sometimes replace unbounded recursive calls with a loop that allocates no storage per call, so a stack failure is not a reliable stopping mechanism. section 15.2.1 section 15.4

A direct translation of the Fibonacci recurrence uses `fib(n-1) + fib(n-2)` and returns 1 for its first two terms. It is short, but its call tree repeats computations: the given time recurrence grows approximately with a power of the golden ratio. A cache records computed terms and gives linear time instead. A second version carries two terms in a buffer, updating them as calls proceed. Recursive syntax alone therefore says little about the amount of work performed. section 7.3

/* Compute Fibonacci number n with the help of a cache that may
   hold previously computed values. */
size_t fibCacheRec(size_t n, size_t cache[static n]) {
  if (!cache[n-1]) {
    cache[n-1]
      = fibCacheRec(n-1, cache) + fibCacheRec(n-2, cache);
  }
  return cache[n-1];
}

size_t fibCache(size_t n) {
  if (n+1 <= 3) return 1;
  /* Set up a VLA to cache the values. */
#if __STDC_VERSION__ > 202311L
  /* Since C23, VLA can be default initialized. */
  size_t cache[n] = { };
#else
  size_t cache[n]; memset(cache, 0, n*sizeof(*cache));
#endif
  /* Non-trivial initialization is replaced by assignment. */
  cache[0] = 1; cache[1] = 1;
  /* Call the recursive function. */
  return fibCacheRec(n, cache);
}

The cached Fibonacci listing makes the tradeoff concrete: an entry is computed recursively only when it has no stored value, then reused by later calls. Its wrapper prepares the cache before starting the recursion. section 7.3

Nesting as recursive descent

A recursive-descent parser handles text inside `{}` by descending when it encounters an opening brace and ascending at a closing brace. Its output replaces brace nesting with progressively deeper indentation. Unlike the arithmetic examples, it also checks whether nesting is too deep before proceeding. section 19.1

How Modern C, Third Edition covers it

How deep it goes
Works through stopping cases, call progress, repeated computation, caching, and failure risks using listings and time recurrences.
Examples
Traces a greatest-common-divisor call, compares three Fibonacci implementations, and uses a brace-indenting recursive-descent parser.
What it assumes
Assumes familiarity with C functions and expressions while explaining why separate parameters and locals exist for simultaneous calls.
What you can do after
Build it from scratch by choosing a stopping case and progressing inputs, then evaluate repeated work and call-resource risks.
How it connects
Connects recursion to function parameters, local variables, Euclid’s algorithm, Fibonacci numbers, caching, recursive-descent parsing, and program failure.

Also explained in

Compare how 23 books explain recursion →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C, Third Edition. The section links point to the parts of the book it draws on.