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
The usual way is
MyType *ptr = malloc(array_size * sizeof *ptr);
But if you want to be compatible with c++, do
MyType *ptr = (MyType*) malloc(array_size * sizeof *ptr);
You can also make a macro
#define MALLOC( NUMBER, TYPE ) ( TYPE * ) malloc( NUMBER * sizeof( TYPE ) )
MyType *ptr = MALLOC(10, MyType);
Of course, with no RAII, make sure sometime later you have
free(ptr);
You may think that what I say is strange, but there is no big difference between C++ and C. C has RAII as well. RAII does not belong to C++ only.
Only thing you should have enough discipline to do management.
C++ class:
class foo {
public:
ofstream ff;
int x,y;
foo(int _x) : x(_x),y(_x){ ff.open("log.txt"); }
void bar() { ff<<x+y<<endl; }
};
int main()
{
auto_ptr<foo> f(new foo);
f->bar();
}
C object
typedef struct FOO {
FILE *ff;
int x,y;
} *foo_t;
foo_t foo_init(int x)
{
foo_t p=NULL;
p=malloc(sizeof(struct FOO)); // RAII
if(!p) goto error_exit;
p->x=x; p->y=x;
p->ff=fopen("log.txt","w"); // RAII
if(!p->ff) goto error_exit;
return p;
error_exit: // ON THROW
if(p) free(p);
return NULL;
}
void foo_close(foo_t p)
{
if(p) fclose(p->ff);
free(p);
}
void foo_bar(foo_t p)
{
fprintf(p->ff,"%d\n",p->x+p->y);
}
int main()
{
foo_t f=foo_init(1);
if(!f) return 1;
foo_bar(f);
foo_close(f);
return 0;
}
I know this is an old post but there hasn't really been much of a comprehensive answer to best practice in terms of style, which I think is what the op really wanted, so here is my take on memory allocation in C. Note I am more of a C++ person so much of my thoughts come from that attitude.
It is often handy to know whether your pointer is allocated, so always assign NULL to a pointer when you declare it. You can also create yourself a safe free function which frees the memory and then assigns NULL to it so you don't have to worry.
If you allocate memory in one C file then you should free it in the same file. This is perhaps more restrictive than needed, however if you are writing a library then you should definitely free any memory within your library that is malloc'd in your library. This is because on Windows dlls have a different heap to the exe, so mallocing memory in a dll and freeing it in the exe corrupts your heap.
By extension and for the sake of symmetry this means if you have a function which returns a pointer to allocated memory then you should have a function which frees that memory. This is why many librarys have an initialisation function which returns a pointer to some data (generally cast as a void *) then a cleanup function which will free the library's resources. If you can malloc and free within the same function then that is good as it makes it easy for you to keep track of things.
Do not try to allocate all your memory at the beginning of a function and then free it at the end. This just means that if you want to return part way through the function you have to free all the memory, whereas if you malloc and free memory as you go you will have fewer pointers to free.
If you often have functions which allocate many pointers, then consider creating and array which holds pointers to all your pointers at the beginning of the function, then have a function that frees them all. This will save you the inevitable "I'll come back and sort my memory leaks later" syndrome if you want to return mid function.
The concept of factories is useful. A factory would be a function which mallocs the memory for a struct, assigns function pointer to the struct, initialises its variables and then returns the pointer to it. If the first of those was a destructor or an array of specific functions then you can have a generic destroy function that can call any struct's destructor, then free the struct's memory. You can also hide some of the internal details of the class by having different inward and outward facing definition of the struct. COM is built upon these principles.
So these are just the ways I look at memory in C. It isn't as elegant as in C++, but as you are relying on humans to deal with it, there are strategies like those above that can make things as simple as possible for them.
Note also that there are always exceptions to every rule - these are just things that I think about when I use C. I'm sure other people have other ideas.
Phil
I don't know how to hide them and how to automate things.
C and C++ are different languages. Now, say that a hundred times to yourself. Be loud.
What do you mean by hiding? What do you mean by automate? Can you post some examples? Why do you need to hide and/or automate.
Good places online to start off with C memory allocation are:
Well in C you have to do all you memory management manually as you already have discovered. That should be no surprise.
The sad truth is that C isn't really designed to encapsulate all those memory management issues.
If you look at fairly high quality APIs like POSIX, you'll see that the common pattern is that you pass a pointer to a pointer to a function, which then allocates the memory, and that you later pass it again to a function that destroys it.
It's not necessarily elegant, but I don't think there are many ways to make it really elegant without simulating OOP in C.