I think I\'ve got a good grasp on how to handle memory in C++ but doing it in C is different I\'m a bit off.
In C++ I\'ve got constructors and destructors, I\'ve got the
Unfortunately there are limited strategies for automating memory allocation and deallocation in C. The C++ compiler generates a lot of code behind the scenes for you -- it keeps track of each variable on the stack and makes sure that the appropriate destructor is called when the stack is cleaned up. This is actually a fairly sophisticated type of code generation, especially when you throw exceptions into the mix.
C on the other hand is much simpler, which is why it's sometimes called "high level assembly language". C doesn't have any mechanism to guarantee that a particular bit of code is called when a function exits or a variable is popped off the stack, so it's up to you to keep track of each bit of memory you allocate and every file or network socket you open and clean them up at the appropriate point. There's no practical way to build an automatic smart pointer in C.
One concept you should look at is "memory pools". Basically, rather that try to keep track of every individual block of memory you allocate, you create a pool, do some chunk of work, placing every memory block you allocate into the pool, then free the whole pool when you're done. You trade off a little bit of performance and control here in order to ease the cognitive load on the programmer, but most of the time it's well worth it.
You should take a peek at the Apache Portable Runtime project. They have a memory pool library (docs at http://apr.apache.org/docs/apr/1.3/group__apr__pools.html ). If APR is too much for you to dive into, you can implement a very simple memory pool using three functions and a linked list data structure. Pseudocode would be something like:
struct Pool {
void* memoryBlock;
struct Pool *next;
}
struct Pool *createPool(void) {
/* allocate a Pool and return it */
}
void addToPool(struct Pool *pool, void *memoryBlock) {
/* create a new Pool node and push it onto the list */
}
void destroyPool(struct Pool *pool) {
/* walk the list, free each memory block then free its node */
}
Using the pool is something like this:
int main(void) {
struct Pool *pool = createPool();
/* pool is empty */
doSomething(pool);
/* pool full of crap, clean it up and make a new one */
destroyPool(pool);
pool = createPool();
/* new pool is empty */
doMoreStuff(pool);
destroyPool(pool);
return 0;
}