qc.hlp (Table of Contents; Topic list)
Important Notice
The pages on this site contain documentation for very old MS-DOS software, purely for historical purposes. If you're looking for up-to-date documentation, particularly for programming, you should not rely on the information found here, as it will be woefully out of date.
HEAPWALK.C
                                             Up Contents Index Back
────────────────────────────────────────────────────────────────────────────
 
/* HEAPWALK.C illustrates heap testing functions including:
 *      _heapchk        _heapset        _heapwalk       _msize
 */
 
#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h>
 
/* Macro to get a random integer within a specified range */
#define getrandom( min, max ) ((rand() % (int)(((max)+1) - (min))) + (min))
 
int _far *heapvalidate( char fill );    /* Prototypes */
void heapstat( int status );
 
void main()
{
    unsigned *p[10];
    int i, _far *perr;
 
    srand( (unsigned)time( NULL ) );  /* Seed with current time */
 
    /* Check heap status. Should be OK at start of heap. */
    heapstat( _heapchk() );
 
    /* Now do some operations that affect the heap. In this example,
     * allocate random-size blocks.
     */
    for( i = 0; i < 10; i++ )
    {
        if( (p[i] = (unsigned *)calloc( getrandom( 1, 10000 ),
                                        sizeof( unsigned ) )) == NULL )
        {
            --i;
            break;
        }
        printf( "Allocated %u at %Fp\n", _msize( p[i] ), (void _far *)p[i] );
    }
 
    /* Fill all free blocks with the test character. */
    heapstat( _heapset( 254 ) );
 
    /* In a real program, you might do operations here on the allocated
     * buffers. Then do heapvalidate to make sure none of the operations
     * wrote to free blocks.
     */
    perr = heapvalidate( 254 );
    if( perr == NULL )
        printf( "Free entries are unchanged.\n\n" );
    else
        printf( "Free entry at %Fp modified.\n\n", perr );
 
    /* Do some more heap operations. */
    for( ; i >= 0; i-- )
    {
        free( p[i] );
        printf( "Deallocating %u at %Fp\n",
                _msize( p[i] ), (void _far *)p[i] );
    }
 
    /* Check heap again. */
    heapstat( _heapchk() );
}
 
/* Tests each block in the heap. If a modified free block is found,
 * returns it's address. Otherwise returns NULL.
 */
int _far *heapvalidate( char fill )
{
    struct _heapinfo hi;
    unsigned heapstatus, i;
    char _far *p;
 
    /* Walk through entries, checking free blocks. */
    hi._pentry = NULL;
    while( (heapstatus = _heapwalk( &hi )) == _HEAPOK )
    {
        /* For free entries, check each byte to see that it still has
         * only the fill character. Return address if changed.
         */
        if( hi._useflag != _USEDENTRY )
        {
            for( p = (char _far *)hi._pentry, i = 0; i < hi._size; p++,i++ )
                if( (char)*p != fill )
                    return hi._pentry;
        }
    }
    return NULL;
}
 
/* Reports on the status returned by _heapwalk, _heapset, or _heapchk */
void heapstat( int status )
{
    printf( "\nHeap status: " );
    switch( status )
    {
        case _HEAPOK:
            printf( "OK - heap is fine" );
            break;
        case _HEAPEMPTY:
            printf( "OK - empty heap" );
            break;
        case _HEAPEND:
            printf( "OK - end of heap" );
            break;
        case _HEAPBADPTR:
            printf( "ERROR - bad pointer to heap" );
            break;
        case _HEAPBADBEGIN:
            printf( "ERROR - bad start of heap" );
            break;
        case _HEAPBADNODE:
            printf( "ERROR - bad node in heap" );
            break;
    }
    printf( "\n\n" );
}