If you get around to covering memory management in C, I suggest teaching people how to use these functions from an old Dr Dobbs magazine (Aug 1990, Debugging Memory Allocation Errors) article on âwrappingâ the memory management functions in order to debug mistakes. These little routines have saved me countless hours debugging both my own code and othersâŚ
/* memMalloc() -- Same as malloc(), but registers activity using memTrack().
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
void *memMalloc(size_t bytes, char *tag)
{
void *allocated;
allocated = malloc(bytes);
memTrack_alloc(allocated, tag);
return(allocated);
}
/* memFree() -- Same as free(), but registers activity using memTrack().
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
void memFree(void *to_free, char *tag)
{
if (memTrack_free(to_free, tag))
{
free(to_free);
}
}
/* MEMTRACK.C -- Module to track memory allocations and frees that occur
* in the other mem...() routines. Global routines:
* memTrack_alloc() -- Records allocations.
* memTrack_free() -- Records attempts to free.
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
static FILE *memTrack_fp(void);
static void memTrack_msg(char *msg);
#define ALLOC 'A'
#define FREE 'F'
/* Track an allocation. Write it in the debugging file in the format
* A 0000:0000 tag */
void memTrack_alloc(void *allocated, char *tag)
{
FILE *fp;
if (fp = memTrack_fp())
{
fseek(fp,0L,SEEK_END);
fprintf(fp,"%c %p %s\n",ALLOC, allocated, tag);
fclose(fp);
}
}
/* Track freeing of pointer. Return FALSE if was not allocated, but tracking
* file exists. Return TRUE otherwise. */
int memTrack_free(void *to_free, char *tag)
{
int rc = 1;
FILE *fp;
void *addr_in_file = 0;
#define MAX_LTH 200
char line[MAX_LTH];
char found = 0;
char dummy;
int ii;
long loc;
if (fp = memTrack_fp())
{
rewind(fp);
for ( loc=0L; fgets(line,MAX_LTH,fp); loc = ftell(fp) )
{
if (line[0] != ALLOC) /* Is the line an 'Allocated' line? */
continue; /* If not, back to top of loop. */
ii = sscanf(line,"%c %p",&dummy, &addr_in_file);
if (ii==0 || ii==EOF)
continue;
/* Is addr in file the one we want? */
if ( (char *)addr_in_file - (char *)to_free == 0 )
{
found = 1;
fseek(fp,loc,SEEK_SET); /* Back to start of line */
fputc(FREE,fp); /* Over-write the ALLOC tag */
break;
}
}
fclose(fp);
if (!found)
{
char msg[80];
sprintf(msg,"Tried to free %p (%s). Not allocated.",to_free,tag);
memTrack_msg(msg);
}
}
return(rc);
}
/* Return FILE pointer for tracking file. */
static FILE *memTrack_fp()
{
static char *ep = NULL; /* Points to environment var that names file */
FILE *fp = NULL; /* File pointer to return */
if (ep == NULL /* First time through, just create blank file */
&& (ep = getenv("MEMTRACK"))
&& (fp = fopen(ep,"w")) )
{
fclose(fp);
fp = 0;
}
if (ep) /* If we have a file name, proceed. */
{ /* Otherwise, do nothing. */
fp = fopen(ep,"r+"); /* Open debugging file for append access. */
if (!fp)
{
fprintf(stderr,"\a\nCannot open %s\n\a",ep);
}
}
return(fp);
}
/* Write a message to the debugging file. */
static void memTrack_msg(char *msg)
{
FILE *fp;
if (fp = memTrack_fp())
{
fseek(fp,0L,SEEK_END);
fprintf(fp,"\n%s\n",msg);
fclose(fp);
}
else
{
fprintf(stderr,"%s\n",msg);
}
}
/* memCalloc() -- Same as calloc(), but registers activity using memTrack().
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
void *memCalloc(size_t num_elems, size_t bytes_per_elem, char *tag)
{
void *allocated;
allocated = calloc(num_elems, bytes_per_elem);
memTrack_alloc(allocated, tag);
return(allocated);
}
/* memRealloc() - Same as realloc(), but registers activity with memTrack().
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
void *memRealloc(void *allocated, size_t bytes, char *tag)
{
memTrack_free(allocated, tag);
allocated = realloc(allocated, bytes);
if (allocated)
{
memTrack_alloc(allocated, tag);
}
return(allocated);
}
/* memStrdup() -- Same as strdup(), but registers activity using memTrack().
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <mem.h>
void *memStrdup(void *string, char *tag)
{
void *allocated;
allocated = strdup(string);
memTrack_alloc(allocated, tag);
return(allocated);
}
/* MEM.H -- ** Copyright (c) 1990, Cornerstone Systems Group, Inc. */
#ifdef MEMTRACK
void *memCalloc(size_t num_elems, size_t bytes_per_elem, char *tag);
void memFree(void *vp, char *tag);
void *memMalloc(size_t bytes, char *tag);
void *memRealloc(void *oldloc, size_t newbytes, char *tag);
void *memStrdup(void *string, char *tag);
/* The next two functions are only called by the other mem functions */
void memTrack_alloc(void *vp, char *tag);
int memTrack_free(void *vp, char *tag);
#else
#define memCalloc(NUM,BYTES_EACH,TAG) calloc(NUM,BYTES_EACH)
#define memFree(POINTER,TAG) free(POINTER)
#define memMalloc(BYTES,TAG) malloc(BYTES)
#define memRealloc(OLD_POINTER,BYTES,TAG) realloc(OLD_POINTER,BYTES)
#define memStrdup(STRING, TAG) strdup(STRING)
#endif
/* DEMOHEAP.C - Demonstrate use of heap...() functions.
* Copyright (c) 1990 - Cornerstone Systems Group, Inc.
*/
#include <stdio.h>
#include <malloc.h>
#include <heap.h>
static void my_own_msg_func(char *msg);
main()
{
char *allocated_but_never_freed;
char *this_one_is_ok;
char *freed_but_never_allocated;
heapPrt_set_msg_func(my_own_msg_func);
allocated_but_never_freed = malloc(10);
heapPrt("after first malloc()");
this_one_is_ok = malloc(20);
heapPrt("after second malloc()");
free(this_one_is_ok);
heapPrt("after first free()");
free(freed_but_never_allocated);
heapPrt("after second free()");
return(0);
}
/* heapPrt() makes its report with puts() by default. This will not be
* appropriate for some applications, so we will demonstrate the use of an
* alternative message function. This one writes to stderr.
* The alternative function should take one argument (a char *). Its
* return value is ignored, so it might as well be void.
*/
static void my_own_msg_func(char *msg)
{
fprintf(stderr,"My own message function: %s\n",msg);
}
OUTPUT:
My own message function: 1 allocations, 10 bytes, after first malloc()
My own message function: 2 allocations, 30 bytes, after second malloc()
My own message function: 1 allocations, 10 bytes, after first free()
My own message function: 1 allocations, 10 bytes, after second free()
/* heap.h - Header file for use with heap...() functions.
* Copyright (c) 1990 - Cornerstone Systems Group, Inc.
*/
void heapPrt(char *tag);
void heapPrt_set_msg_func(void (*new_msg_func)() );
void heapUsed(unsigned int *numused, long *totbytes);
/* HEAPUSED.C -- Tell how much of heap has been used. For use with MS C 5.x
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <malloc.h>
#include <heap.h>
void heapUsed(
unsigned int *numused,
long *totbytes)
{
struct _heapinfo hinfo;
int status;
*numused = 0;
*totbytes = 0L;
hinfo._pentry = (char *)0;
while ( (status=_heapwalk(&hinfo)) == _HEAPOK)
{
if (hinfo._useflag == _USEDENTRY)
{
++ (*numused);
*totbytes += hinfo._size;
}
}
}
/* HEAPPRT.C -- Print summary information about heap. For use with MS C 5.x
* This module contains two functions:
* heapPrt() prints the summary information.
* heapPrt_set_msg_func() allows you to specify a function for heapPrt()
* to use, other than printf().
* Copyright (c) 1990, Cornerstone Systems Group, Inc.
*/
#include <stdio.h>
#include <malloc.h>
#include <heap.h>
static void (*heapPrt_msg_func)() = 0;
/*--------------------------------------------------------------------------*/
void heapPrt(
char *tag) /* Description of where you are in processing */
{
unsigned int numused; /* Number of allocations used */
long totbytes; /* Total bytes allocated */
char msg[80]; /* Message to display */
heapUsed(&numused, &totbytes);
if (!heapPrt_msg_func)
heapPrt_msg_func = puts;
sprintf(msg, "%5u allocations, %6ld bytes, %s",numused,totbytes,tag);
heapPrt_msg_func(msg);
}
/*--------------------------------------------------------------------------*/
void heapPrt_set_msg_func(
void (*new_msg_func)())
{
heapPrt_msg_func = new_msg_func;
}
/*--------------------------------------------------------------------------*/