Hi
So I didn't discourage you... damn... ;-)
It is mayby not that hard to explain, but it surely takes time to describe all the details. I'll try to be short and clear:
realloc() solves you two problems:
1. it manages the memory for you (allocates new buffer, frees the old one, whenever needed).
2. if its needed, it performs a copy of the old buffer to the new one.
From the logical point of view you may think that realloc() always allocates new buffer, performs the copy and frees the old buffer.
But do you remember what I've written earlier about internal calls to OS? The allocated buffer is almost always bigger than requested by the programmer, but you don't know how much bigger.
You do not know. But realloc() can find it out. If really allocated buffer is big enough to serve the new value requested by the programmer (as second argument to realloc()), it is simply not needed to allocate, copy and free. So it happens - if only possible, the old buffer is returned as the new one and no more actions are made. What a great speedup!
You must know that memory allocation is quite difficult task for OS - it must check all free buffers and find the best one (and how to define the best one? the first found that is big enough? and how much of it should be returned?). So for that reasons you shouldn't allocate memory too often (not every single byte).
I have also to mention that the code I wrote is quite effective for what is needed in your code. I mean for transfering of some strings you don't need more complicated memory management. Notice that I defined relatively big INCREMENT (256 bytes), so I guess most of cases it would be enough to allocate only once. More complicated memory management would be needed if you had heavy transfers - a lot of data to read and write, and in unpredictable order.
This solution has also one more advantage dedicated for strings - it keeps all the content in single block, so it is always ready to be printed directly by simply using stdio functions without any tricks.
So for that purposes even professional programs would go this way.
If you're interested in more complicated memory management - this is not that much related with the OS at this level. You just have to learn about basic programistinc structures like lists, trees and hash-tables. Then practice, practice and practice to be able to use them intuitively and without mistakes (which are quite easy to be done and very hard to find afterwards in the working code). Then you'll find always the good answer for every programistic question you'll have while programing.
To explain those data structures it is always better to draw the pictures than to explain everything with plain words - it just simply doesn't work too well on the imagination that way.
All the best on your quest. :-)