Simple rules to avoid Memory Leaks in C

Below are several short tips which will help you survive C programming.

The most terrifying aspect of the C programming language is closely related to it’s core strength. Programming in C is all about using pointers – which are memory locations. Thus, in C, when you need a variable to work with to store numbers and manipulate them, you don’t have to deal with the variable directly – you use it’s address, instead. This is, of course, a really stupid thing to do when you just have to use a single variable to store a single number. But it is an enormously useful strategy when sending that variable off to a distant procedure, or when dealing with large arrays.

The great strength of the C programming language is in this use of pointers. You can add them, multiply them, crunch them, and control them. They are at your hands. But with great power comes great responsibility. The trouble with the C programming language is that it is all too easy to misuse the power endowed upon you by the compiler. A stray pointer might point to a wrong place. Sometimes it points at a very critical place in your computer, and carelessly manipulating the data where it points might lead to computer crashes, data corruption, and worse. There is also the danger of memory leaks. This happens when the programmer asks the system to hand him a block of computer memory, reserved for his uses, untouchable by other processes. The system returns the pointer to the beginning of the memory block, and reserves the block. The is done using the C command “malloc”. The programmer needs to return that pointer back to the system, so that the memory block can be returned to the general memory pool. This is done vie the appropriately named “free” procedure. Often enough, the programmer forgets to call “free”. Or, if he does, he is using the wrong address.

These problems are so scary for programmers and system administrators, that most modern-day programming languages no longer allow you to roam freely in the world of memory addresses. These days, writing C# or JAVA, the pointers are hidden by the compiler, so that the programmer does not use them directly. this seems to save the programmer some amount of head-ache. But I personally feel, each time I use either of these modern languages, like a person confined to a wheelchair. Sure, I can go places. But it is cumbersome and inconvenient.

So, assuming that you wish, like I do, to write good old C code without all the needless bickering, but you also wish to avoid memory leaks, here are some simple rules which will help you save face:

Rule 1: Always write “free” just after “malloc”

This one should be trivial.

Suppose you want to manipulate an array of integers. You need to allocate them. So you write “malloc”. Don’t wait. Jump to the next line and free the memory.

int *p = (int*) malloc ( sizeof(int) * n );
free (p);

Now go in between and write your code:

int *p = (int*) malloc ( sizeof(int) * n );
//... do your stuff
free (p);

That way you never forget to free memory.

Rule 2: Never, ever, work with the allocated pointer. Use a copy!

Do not use the allocated pointer for doing stuff. Do not even use it to access memory. Always copy it first, and use only the copy in your code.

int *p_allocated = (int*) malloc ( sizeof(int) * n );
int *p_copy = p_allocated;
// do your stuff with p_copy, not with p_allocated!
// e.g.:
while (n--) { *p_copy++ = n; }
...
free (p_allocated);

Thus you are safe from [accidentally] changing the pointer and returning the wrong address over to free. You can freely play with the p_copy pointer, like in the example above.

Trust me, this small tip will save you endless trouble.

Rule 3: Don’t be parsimonious. Use more memory.

Always start by allocating more memory than you need.  After you finish debugging, go back and cut on memory use. If you need an array 1000 integers long, allocate 2000, and only after you make sure everything else is OK – only then go back and cut it down to 1000.

Rule 4: Always carry array length along with you

Wherever your array goes, there should go with it it’s length. A nice trick is to allocate an array sized n+1, and save n into it’s 0 place:

int *p_allocated = (int*) malloc ( sizeof(int) * (n+1) );
int *p_copy = p_allocated+1;
p_copy[-1] = n;
// do your stuff with p_copy, not with p_allocated!
free (p_allocated);

This way the array length is kept before the first place-holder of the array. This is somewhat dangerous, but it can make things easier.

Rule 5: Be consistent. And save comments

The most important thing is to be consistent and to write down what you do. I am always amazed at how many programmers seem to think that comments are a waste of time. They are imperative. Without comments, you probably won’t remember what you did. Imagine returning to your code a year after you wrote it, and spending  countless hour trying to recall what that index does. Better to spend a couple of seconds writing it down.

Also, if you are consistent, you will not fail often. Always use the same mechanism for passing arrays and pointers. Don’t change the way you do things lightly. If you decide to use my previous trick, use it everywhere, or you might find yourself referring back to a nonexistent place because you forgot what type of reference you chose.

Advertisement

,

  1. #1 by kinda on May 10, 2011 - 5:45 am

    hi,
    the rule 2 seems wrong.

    int *p_copy = p_allocated; //only copy the first element in the array.

  2. #2 by mousomer on May 10, 2011 - 11:14 am

    No. Note the difference:

    int p = val;

    defines p to be an integer, and inserts (integer) val into p.

    int p = *adrs;

    defines p to be an integer, and inserts the (integer) value from the address adrs points to, into p.

    When you write

    int* p

    then p is no longer an integer. It is a pointer. So:

    int p_copy = p_allocated; // define p_copy as int, and copy (integer) value from p_allocated into it.

    int p_copy = *p_allocated; // define p_copy as int and copy first element from p_allocated into it.

    int * p_copy = p_allocated; // define p_copy as pointer to integer, and copy p_allocated (an address) into it – this is the correct use.

    int * p_copy = *p_allocated; // a dangerous error: put the value of p[0] as an address into pointer p_copy.

  3. #3 by Gidi on May 10, 2011 - 3:08 pm

    All is good and well BUT there is a fundamental error in your code in tip #2…

    1. In the “malloc” call the functions return value needs to be casted into the recieving pointer type – i.e – There should be an asterix in the casting..

    int *p_allocated = (int*) malloc ( sizeof(int) * n ); // Mind the difference, an asterix after the int in the casting pharen..

    2. The assigning of ” int *p_copy = p_allocated; ” simply assigns the RHS value in the LHS, thus actually STILL working on the original array and will modify it (what you were trying to avoid). To copy the entire array try something like:

    int *p_allocated = (int*) malloc ( sizeof(int) * n );
    int *p_copy = (int*) malloc ( sizeof(int) * n );

    for(int i = 0; i < n; i++)
    {
    *(p_copy + i) = *(p_allocated + i);
    }

    which will actually copy the whole of the array and enable you to modify the copy without wirry….

    • #4 by mousomer on May 10, 2011 - 5:09 pm

      1. Got me there… amended. Thanks.
      2. You missed the point. Is it written better now? The whole idea is that you have good reasons to play with the pointer to an array. Sometimes you might change it by mistake (like writing p=something when you wanted *p=something). By working with a copy of the pointer, you save the original memory address no matter what manipulation you did on the way.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.