K&R has many good examples of real programs. For instance, on page 115 of the Second Edition there are two simple implementations of the echo
command. From there, it might be interesting to see how the command was implemented over time. For instance, there is a version in the GNU coreutils source. A version derived from BSD can be found in BusyBox source.
It might be interesting to see how the newer versions compare to the textbook examples. Why are the programs that are used in real life longer? How much of the code is related to new features and how much is related to dealing with edge cases? How would you write the same code in Java?