How it works exactly is compiler dependent. It may also depend on whether or not you are building with debugging information turned on.
free is going to release memory that you've allocated and return it to the heap for reallocation. Generally, the memory manager as a linked list of blocks of memory that it has allocated. It is going to search the list for your block of memory, remove the link from the allocated list and insert it in the list of free blocks of memory. It may also attempt to merge you block with adjacent blocks of free memory to maximize the size of available blocks.
If you are running Microsoft C++, the debug memory manager will check a couple of bytes that are added to the front and back of the block to be sure that you haven't overflowed when you used it. It will also write a specific byte pattern to the block so that it is easily recognized as deallocated if you use a pointer to it after it has been released.