Perfect, thanks. If anyone's interested this was for creating a behind-the-scenes method of solving memory leak issues. Dangling pointers are handled as well. Below is an example of a fictional library that incorporates these ideas. Code that handles dangling pointers will be highlighted in blue, and code that handles memory leaks will be highlighted in green.

Code:
/* TransUnit.h */

#ifndef _TRANS_UNIT_H_
#define _TRANS_UNIT_H_

#include <stddef.h>

typedef
    struct TransUnit *
    TransUnit_p;

TransUnit_p TransUnit_Create(void);
void        TransUnit_Destroy_(TransUnit_p unit);

#ifdef NDEBUG
#define TransUnit_Destroy(p) TransUnit_Destroy_(p)
#else
#define TransUnit_Destroy(p) do { TransUnit_Destroy_(p); (p) = NULL; } while (0)
#endif

#endif
Code:
/* TransUnit.c */

#include "TransUnit.h"
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>

struct TransUnit {
    /* whatever */
};

#ifndef NDEBUG
static int          RegisteredCheckMemLeak = 0;
static unsigned int TransUnitAllocations = 0;
static void         CheckMemLeak(void);
#endif



TransUnit_p
TransUnit_Create(void)
{
    TransUnit_p unit;

    unit = malloc(sizeof(struct TransUnit));
    if (unit == NULL)
        return NULL;

#ifndef NDEBUG
    if ( ! RegisteredCheckMemLeak ) {
        atexit(CheckMemLeak);
        RegisteredCheckMemLeak = 1;
    }
    TransUnitAllocations++;
#endif

    return unit;
}

void
TransUnit_Destroy_(TransUnit_p unit)
{
    assert(unit != NULL);
    free(unit);

#ifndef NDEBUG
    TransUnitAllocations--;
#endif
}

#ifndef NDEBUG
void
CheckMemLeak(void)
{
    assert(TransUnitAllocations == 0);
}
#endif
Now a few main functions to test.
Code:
#include "TransUnit.h"

int
main(void)
{
    TransUnit_p unit_a, unit_b, unit_c;

    unit_a = TransUnit_Create();
    unit_b = TransUnit_Create();
    unit_c = TransUnit_Create();

    TransUnit_Destroy(unit_a);
    TransUnit_Destroy(unit_b);
    TransUnit_Destroy(unit_c);

    return 0;
}
All is nice and tidy. Program executes smoothly.
Code:
#include "TransUnit.h"

int
main(void)
{
    TransUnit_p unit_a, unit_b, unit_c;

    unit_a = TransUnit_Create();
    unit_b = TransUnit_Create();
    unit_c = TransUnit_Create();

    TransUnit_Destroy(unit_a);
    TransUnit_Destroy(unit_b);
    TransUnit_Destroy(unit_c);

    TransUnit_Destroy(unit_a);  /* whoops */

    return 0;
}
Attempting to work with a dandling pointer. Program terminates with a failed assertion.
Code:
#include "TransUnit.h"

int
main(void)
{
    TransUnit_p unit_a, unit_b, unit_c;

    unit_a = TransUnit_Create();
    unit_b = TransUnit_Create();
    unit_c = TransUnit_Create();

    TransUnit_Destroy(unit_a);
    TransUnit_Destroy(unit_b);
                                /* whoops */

    return 0;
}
Forgot to deallocate memory. Program terminates with a failed assertion.

Additionally, all debugging code is enclosed in preprocessing directives, so once you have worked out all the bugs in your program you can compile your code with the -NDEBUG flag, which will leave you with a compact, clean and efficient program.