So far we have worked with immutable lists. We have never changed the contents of any of the fields of any of our list nodes. Hence the name immutable -- or non-changeable. The positive aspect of using immutable lists is that they are much less error-prone than the kinds of lists where we assign new values to data fields, or even reassign fields containing pointers. It is an observation of human nature that very few of us are capable of manipulating such fields without creating subtle and hard-to-track-down mistakes. While immutable lists are less error-prone, they do have a down side: If you are not careful you can use up all the memory available to your program, and thereby render it useless for reasonably sized applications.
Here is code for doubling every int within a list of ints:
IntNodePtr dubble(IntNodePtr p) { if (p == NULL) return p; else return insert(2*p->myInt, dubble(p->next)); }
It's pretty easy to understand:
The good thing is it's easy to understand and to prove correct. That's typical of programs involving immutable lists. The downside is that it creates a new node for every int that it doubles. Look carefully at the code for insert() and you'll see that it makes a call to malloc().
Look at your code for delete(), for replace(), and for replaceAll(). Study it so you can understand how much garbage they generate.
Many programming paradigms encourage the use of immutable lists. Typically they will incorporate an automated garbage collector. For example, in Java, you never have to worry about the kind of memory leaks we have been describing above. The runtime Java system incorporates a thread that does nothing but search your address space for memory nodes that are no referenced by your executing code. These garbage nodes are returned to the pool available for allocation again. By the way, Java uses new to allocate memory nodes, analagous to the less sophisticated malloc() of C. The thread in Java that reclaims garbage is called, naturally enough, the garbage collector.
Here is the Wikipedia article on memory leaks. It contains a simple program that fails to free some memory it has allocated.
Here is the version of dubble() we would use if we were using mutable lists:
void dubble(p) IntNodePtr p; { if (p == NULL); /* do nothing */ else { p->myInt *= 2; dubble(p->next); } }
Next time, we will some more look at programming with mutable dynamic structures. That is the common C idiom.