Advanced Example 
 
Now it is time to show how to use C Memory Scavenger in a more advanced situation. 
 
This example, like the first one, is a console application. However, in contrast to that example, here the application is the driving part towards the Monitor, i.e., the application takes the initiative to report data to the Monitor. It is designed to be runnable on both the Windows platform and on the Solaris platform. On Windows, the macro WIN32 is supposed to be defined, and on Solaris, it is supposed not to be defined. This is how we separate platform dependent code for the compiler. The example will demonstrates most of the capabilities of the CMemScav Library functions. It consists of a main function launching some threads and calling a couple of functions. Memory will be allocated both from within the threads and in the main function and some memory leaks will be left to clean up. 
 
About the code 
 
The reader is supposed to have studied the Simple Example, where some basic knowledge of CMemScav is described, and will not be repeated here. 
 
Much of the explanation of the code is already within the code, in form of printf() commands, giving this info directly on the console, when running the demo. Therefore, please study the code carefully, run the code and read all comments on the console. Here we give a summary of the code and what will happen when running the code. 
 
  • The application is divided into two files: Advanced.c and DemoFunction.c. In the first file, the main() function is defined, together with the function threadFunc(), which is run in some threads from the main() function. In the other file, the function blackBox() is defined. 
  • First is demonstrated what CMemScav monitors and misses, depending on when and how CMemScav is initialized and switched on/off, using the methods CMemScavInit() and CMemScavSet()
  • Next follows three examples how to free memory by calling CMemScavFreeThese() in different ways. The first demonstrates how memory allocations could be selected by choosing specific source code files and/or specific source code lines. The second example shows how to pick allocations from the sizes of the allocations. Finally, and perhaps the most powerful example, demonstrates how to sort according to indexes and thread ids. This example also indicates how the summary is done, which is the output from CMemScavShowStatus()
  • After this, an example is given showing how to call CMemScavGetListEntry() to get the same information within the application, as is given only as output using CmemScavShowList(), or clicking at the "Get list of allocations"-button in the Monitor. Note that using CMemScavGetListEntry(), all data is retrieved "programatically", i.e., integer values are put in int variables, strings in char* and so on, so that the data may be used within the program, and not only displayed. 
  • The next example demonstrates how the Monitor might be used to automatically create calls to CMemScavFreeThese(). However, this should perhaps more be seen as examples how such calls could look like, rather than really chosing exactly the output from the Monitor
  • The final example lets the user test the possibility to free memory allocations from the Monitor
  •  
    Before showing the code list for this example, note that together with this example and the Simple Example, found among the downloadable files, there is another example, called StressTest.c. This one is not described on these pages, but having studied the other two examples, it should not be hard to understand how it works. It demostrated the usage of C Memory Scavenger in a truly multi threaded environment. It launches 250 threads, which randomly allocate memory using all memory allocating functions CMemScav monitors and intentionally "forgets" to clean up some allocations. Eventually, it uses CMemScav and the Monitor to clean up the rest, in several ways. 
     
    Code List of Advanced.c 
     
    /******************************************************************** 
    * Platform specific include statements 
    *******************************************************************/ 
    #ifdef WIN32 
     #include <windows.h> 
    #else 
     #include <stdlib.h> 
     #include <pthread.h> 
    #endif 
     
    /******************************************************************** 
    * Platform independent include statements 
    *******************************************************************/ 
    #include <stdio.h> 
    #include <string.h> 
    #include <time.h> 
    #include "CMemScav.h" 
     
    /* All in C */ 
    #ifdef __cplusplus 
     extern "C" 
     { 
    #endif 
     
    #define NO_THREADS 3 
    const int THREAD_LOOP_MAX = 25; 
    int totalMalSize[NO_THREADS]; 
    int totalCalSize[NO_THREADS]; 
    int totalReaSize[NO_THREADS]; 
    int totalDupSize[NO_THREADS]; 
     
    /******************************************************************** 
    * Declaration of function in DemoFunction.c 
    *******************************************************************/ 
    void blackBox(); 
     
    /******************************************************************** 
    * Definition of local function to be run in some threads 
    *******************************************************************/ 
    #ifdef WIN32 
     DWORD WINAPI threadFunc(void *arg) 
    #else 
     void *threadFunc(void *arg) 
    #endif 
     // Declarations 
     // ------------ 
     int n; 
     int index = *(int*)arg; // This is why we use idx[...] in main() instead of n 
     int malSize; 
     int calSize; 
     int reaSize; 
     int dupSize; 
     char *malTxt = NULL; 
     void *calPtr = NULL; 
     char *dupTxt = NULL; 
     float probForMemoryLeak = 10.0; // In percent (%) 
     int memLeakLimit = (int)((RAND_MAX+1)*(100.0 - probForMemoryLeak)/100.0) - 1; 
     
     // Initialize the rand function differently for each time and each thread 
     // ---------------------------------------------------------------------- 
     srand((unsigned)time(NULL) + (unsigned int)&n); // n thread specific 
     
     for (n = 0; n < THREAD_LOOP_MAX; n++) 
     { 
       // Allocate some memory 
       // -------------------- 
     
       // Malloc 
       // ------ 
       malSize = rand(); 
       if (malSize == 0) malSize = 1; 
       malTxt = (char*) malloc(malSize); 
       totalMalSize[index] += malSize; 
       memset(malTxt, '*', malSize - 1); malTxt[malSize - 1] = 0; // Use the memory 
     
       // Calloc 
       // ------ 
       calSize = rand(); 
       calPtr = calloc(1, calSize); 
       totalCalSize[index] += calSize; 
     
       // Realloc 
       // ------- 
       reaSize = rand(); 
       if (reaSize < 2) reaSize = 2;  // realloc assumes at least one byte 
       malTxt = (char*)realloc(malTxt, reaSize); 
       totalMalSize[index] -= malSize; // The bookkeeping of the memory is now 
       totalReaSize[index] += reaSize; // moved from malloc to realloc. 
       memset(malTxt, '*', reaSize - 1);  malTxt[reaSize - 1] = 0;  // Use the memory 
     
       // Strdup 
       // ------ 
       dupTxt = strdup(malTxt); 
       dupSize = strlen(dupTxt) + 1; 
       totalDupSize[index] += dupSize; 
     
       // Now free some of the memory, but not all, leaving some "memory leak" 
       // with the probability: probForMemoryLeak for each memory chunk. 
       // -------------------------------------------------------------------- 
       if (rand() <= memLeakLimit) 
       { 
         free(malTxt); 
         totalReaSize[index] -= reaSize; 
       } 
     
       if (rand() <= memLeakLimit) 
       { 
         free(calPtr); 
         totalCalSize[index] -= calSize; 
       } 
     
       if (rand() <= memLeakLimit) 
       { 
         free(dupTxt); 
         totalDupSize[index] -= dupSize; 
       } 
     } 
     
     // Exit 
     // ---- 
     #ifdef WIN32 
       return 0; 
     #else 
       return NULL; 
     #endif 
     
    /******************************************************************** 
    * The main function. 
    *******************************************************************/ 
    int main(int argc, char** argv) 
     // Declarations 
     // ------------ 
     BigInt size; // BigInt = __int64 in Windows and long long in Solaris, see CMSPlatforms.c 
     BigInt startIndex, stopIndex; 
     void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5; 
     CMSData *cmsData; 
     enum CMSMemoryAccess acc; 
     int startLine; 
     int stopLine; 
     int memLeakSummary = 0; 
     int memoryMalSize = 0; 
     int memoryCalSize = 0; 
     int memoryReaSize = 0; 
     int memoryDupSize = 0; 
     int n; 
     int idx[NO_THREADS]; 
     #ifdef WIN32 
       DWORD threadId[NO_THREADS]; 
       HANDLE tHandles[NO_THREADS]; 
     #else 
       pthread_t threadId[NO_THREADS]; 
     #endif 
     
     srand((unsigned)time(NULL) + (unsigned int)&n); // n thread specific 
     
     // ******************************************************************* 
     printf("See the source code Advanced.c and DemoFunction.c, "); 
     printf("while running this demo.\n\n"); 
     printf("Hit ENTER to start the demo...\n"); 
     getchar(); 
     printf("Demo of having CMemScav ENABLED or DISABLED\n"); 
     printf("-------------------------------------------\n"); 
     printf("Five malloc calls will be done, three in DISABLED mode and\n"); 
     printf("two in ENABLED mode. Therefore, only two will be monitored\n"); 
     printf("by CMemScav. Output will be printed here to show these two\n"); 
     printf("allocations, ptr3 and ptr5 in the code.\n"); 
     printf("NB! Do NOT connect to this application from the Monitor yet.\n"); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     // ******************************************************************* 
     
     ptr1 = malloc(rand()); // Not monitored, since CMemScav is not initialized nor enabled 
     CMemScavInit(FALSE, FALSE, NULL, 0); // Initialized but not enabled (first arg = FALSE). 
     ptr2 = malloc(rand()); // Not monitored, since CMemScav is not enabled 
     CMemScavSet(TRUE, FALSE); // CMemScav is now enabled (first arg = TRUE). 
     ptr3 = malloc(rand()); // Monitored, since CMemScav is both initialized & enabled. 
     
     CMemScavSet(FALSE, FALSE); // Switch off CMemScav 
     ptr4 = malloc(rand());// Not monitored, since CMemScav is disabled 
     CMemScavSet(TRUE, FALSE);  // Switch on CMemScav 
     ptr5 = (void*)strdup("xxx"); // Monitored, since CMemScav is enabled. 
     
     CMemScavShowStatus(AllCalls); 
     CMemScavShowList(); // Only ptr3 and ptr5 monitored. The list is displayed on the 
                         // console, since no connection to the Monitor is so far setup. 
     
     printf("Above is displayed the list of monitored memories, i.e.,\n"); 
     printf("ptr3 and ptr5. The list came here, because no connection to\n"); 
     printf("the Monitor exists yet. Now launch the Monitor and connect\n"); 
     printf("to this application. Then click at the 'Get list of allocations'\n"); 
     printf("button, to see the same list as is displayed above. Note that\n"); 
     printf("only the pointers ptr3=%p and ptr5=%p are monitored.\n", ptr3, ptr5); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     
     CMemScavFreeAll(); // Will only free ptr3 and ptr5 
     free(ptr1); // CMemScav will note that three calls to free are done here, 
     free(ptr2); // which memories were not monitored. See "Not monitored 3" 
     free(ptr4); // in the Monitor's Summary down to the left. 
     printf("'Manually', ptr1, ptr2, and ptr4 have to be freed by calls to\n"); 
     printf("free(), while ptr3 and ptr5 may be freed by a call to\n"); 
     printf("CMemScavFreeAll(), see the result in the Monitor.\n"); 
     CMemScavShowList(); 
     printf("Note the 'Not monitored 3' in the Monitor down to the left,\n"); 
     printf("due to the 3 calls to free() of ptr1, ptr2, and ptr4, which\n"); 
     printf("were not monitored by CMemScav.\n\n"); 
     printf("By the way, below \"Not monitored\", you can see \"Internal Use\",\n"); 
     printf("which always tells how much memory CMemScav uses internally\n"); 
     printf("to store necessary data. It is always greater then 0 after the\n"); 
     printf("call to CMemScavInit and before the call to CMemScavFinish.\n"); 
     printf("The more allocations monitored, the greater the internal use.\n"); 
     printf("Much of this is due to the storage of the full paths to the\n"); 
     printf("source files. This is what you have to pay in memory usage\n"); 
     printf("to get the facility to prevent leakage.\n"); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     
     // ******************************************************************* 
     printf("How to use args 1-3 in CMemScavFreeThese\n"); 
     printf("----------------------------------------\n"); 
     // ******************************************************************* 
     startLine = __LINE__; // Get line number to embrace some code 
     ptr1 = malloc(rand());   
     blackBox(); // Allocate some memory in a function in the file DemoFunction.c 
     ptr2 = malloc(rand());   
     stopLine = __LINE__;  // Get line number to embrace some code 
     CMemScavShowList(); 
     printf("Some memory is now allocated both in Advanced.c and in\n"); 
     printf("DemoFunction.c, see the Monitor. Memory generated in Advanced.c\n"); 
     printf("between lines %d and %d will now be freed. ", startLine, stopLine); 
     printf("Note that these \nwill disappear in the Monitor.\nHit ENTER to go on...\n"); 
     getchar(); 
     CMemScavFreeThese("Advanced.c", startLine, stopLine, 0, 0, 0, 0, 0); 
     CMemScavShowList(); 
     
     printf("All memory generated in DemoFunction.c, regardless of line numbers,\n"); 
     printf("will now be freed. Note that these will disappear in the Monitor.\n"); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     size = CMemScavFreeThese("DemoFunction.c", 0, 0, 0, 0, 0, 0, 0); 
     printf("Released memory in latest call to CMemScavFreeThese: "); 
     #ifdef WIN32 
       printf("%I64iB\n", size); // Note how to print a BigInt (__int64) in Windows 
     #else 
       printf("%lliB\n", size);  // Note how to print a BigInt (long long) in Solaris 
     #endif 
     CMemScavShowList(); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     
     // ******************************************************************* 
     printf("How to use args 4-5 in CMemScavFreeThese\n"); 
     printf("----------------------------------------\n"); 
     // ******************************************************************* 
     for (n = 0; n < 10; n++) 
     { 
       blackBox(); // Allocate some memory of size between 1 and RAND_MAX+1 
     } 
     CMemScavShowList(); 
     printf("Some memory pieces of sizes between 1 and %d are allocated,\n", RAND_MAX+1); 
     printf("see the Monitor's list. Click at 'Memory (B)' to sort\n"); 
     printf("the list according to this column. One more click,\n"); 
     printf("and the sorting is reversed.\nHit ENTER to go on...\n"); 
     getchar(); 
     
     printf("Smaller half of these memory chunks will now be freed, i.e.,\n"); 
     printf("between 1B and %dB. Hit ENTER to go on...\n", RAND_MAX/2); 
     getchar(); 
     CMemScavFreeThese(NULL, 0, 0, 1, RAND_MAX/2, 0, 0, 0); 
     CMemScavShowList(); 
     
     printf("Bigger half of these memory chunks will now be freed, i.e.,\n"); 
     printf("between %dB abd %dB. Hit ENTER to go on...\n", RAND_MAX/2, RAND_MAX+1); 
     getchar(); 
     CMemScavFreeThese(NULL, 0, 0, RAND_MAX/2, RAND_MAX+1, 0, 0, 0); 
     CMemScavShowList(); 
     
     // ******************************************************************* 
     printf("How to use args 6-8 in CMemScavFreeThese\n"); 
     printf("----------------------------------------\n"); 
     // ******************************************************************* 
     // Create and launch some threads running threadFunc 
     // - - - - - - - - - - - - - - - - - - - - - - - - - 
     printf("Three threads will be launched, all executing the function\n"); 
     printf("threadFunc. This function will allocate some memory pieces\n"); 
     printf("and free some but not all of these. Hit ENTER to go on...\n"); 
     getchar(); 
     
     startIndex = CMemScavGetIndex(); // Save index before launching the threads 
     for (n = 0; n < NO_THREADS; n++) 
     { 
       totalMalSize[n] = 0; 
       totalCalSize[n] = 0; 
       totalReaSize[n] = 0; 
       totalDupSize[n] = 0; 
       idx[n] = n; // Send the address of idx[n] instead of the address 
                   // of n below, because n will soon change value. 
       #ifdef WIN32 
         tHandles[n] = CreateThread(NULL, 0, threadFunc, &idx[n], 0, &threadId[n]); 
       #else 
         pthread_create(&threadId[n], NULL, threadFunc, &idx[n]); 
       #endif 
     } 
     
     // Wait for the threads to finish 
     // - - - - - - - - - - - - - - - 
     for (n = 0; n < NO_THREADS; n++) 
     { 
       #ifdef WIN32 
         WaitForSingleObject(tHandles[n], INFINITE); 
       #else 
         pthread_join(threadId[n], NULL); 
       #endif 
     } 
     stopIndex = CMemScavGetIndex(); // Save index after the threads have finished 
     
     // Calc. the sum of allocations, like CMemScav does 
     // - - - - - - - - - - - - - - - - - - - - - - - - 
     for (n = 0; n < NO_THREADS; n++) 
     { 
       memoryMalSize += totalMalSize[n]; 
       memoryCalSize += totalCalSize[n]; 
       memoryReaSize += totalReaSize[n]; 
       memoryDupSize += totalDupSize[n]; 
     } 
     memLeakSummary = memoryMalSize + memoryCalSize + memoryReaSize + memoryDupSize; 
     
     // Show the calculations done both by this program and by CMemScav 
     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
     printf("From malloc:       %dB\n", memoryMalSize); 
     printf("From calloc:       %dB\n", memoryCalSize); 
     printf("From realloc:      %dB\n", memoryReaSize); 
     printf("From strdup:       %dB\n", memoryDupSize); 
     printf("Total memory leak: %dB\n", memLeakSummary); 
     printf("See above what threadFunc has leaked. Note that since realloc\n"); 
     printf("has been called for all memory malloc has been created, all\n"); 
     printf("allocations done by malloc and later reallocated by realloc, have\n"); 
     printf("been bookkept on realloc, hence no memory is now bookkept on\n"); 
     printf("malloc. Compare with the Monitor.\nHit ENTER to go on...\n"); 
     CMemScavShowList(); 
     getchar(); 
     
     // Now use the indexes together with a thread id to clean up after each thread 
     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
     printf("Will now clean up after each thread for indexes [%d, %d].\n", 
       (int)startIndex, (int)stopIndex); 
     for (n = 0; n < NO_THREADS; n++) 
     { 
       printf("Hit ENTER to clean up after thread with id=%d...\n", 
         threadId[n]); 
       getchar(); 
       CMemScavFreeThese(NULL, 0, 0, 0, 0, threadId[n], startIndex, stopIndex); 
       CMemScavShowList(); 
     } 
     
     // ******************************************************************* 
     printf("How to iterate through monitored data, using CMemScavGetListEntry\n"); 
     printf("-----------------------------------------------------------------\n"); 
     // ******************************************************************* 
     printf("Some memory will be allocated, but instead of displaying the data\n"); 
     printf("with CMemScavShowList(), we will demonstrate how to manually\n"); 
     printf("iterate through the data using CMemScavGetListEntry().\n\n"); 
     printf("First, call CMemScavGetListEntry() with either EntryFirst or\n"); 
     printf("EntryLast as argument, to lock the list (a mutex is used) and to\n"); 
     printf("get the first (or last) entry. All entries are CMSData structs\n"); 
     printf("and we will extract the same data from these structs as is\n"); 
     printf("displayed by CMemScavShowList().\n\n"); 
     printf("To get the next or previous entry in the list, call\n"); 
     printf("CMemScavGetListEntry() with EntryNext or EntryPrev as argument.\n\n"); 
     printf("Finally, call this function with the argument EntryFinish when\n"); 
     printf("no further entries should be fetched. This is important, since\n"); 
     printf("this function will unlock the mutex which was locked at the\n"); 
     printf("beginning. This mutex is always used when the list is going to\n"); 
     printf("be updated, as is done whenever malloc, calloc, ..., free are\n"); 
     printf("called. Hence, No other thread can call these functions while\n"); 
     printf("CMemScavGetListEntry() is used to extract entries. It is not\n"); 
     printf("recommended to do this in the same thread either, since you\n"); 
     printf("may corrupt the list you are traversing.\n"); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     
     // Allocate some memory 
     // - - - - - - - - - - - - - - - - - - - - - - - - - 
     blackBox(); 
     
     // Traverse the list of entries created by CMemScav, 
     // from the beginning to the end, to show all entries 
     // - - - - - - - - - - - - - - - - - - - - - - - - - - 
     cmsData = CMemScavGetListEntry(EntryFirst); // or EntryLast 
     while (cmsData != NULL) 
     { 
       printf("File       = %s\n", (*cmsData).file); 
       printf("Line       = %d\n", (*cmsData).line); 
       printf("Mem Type   = "); 
       acc = (*cmsData).acc; // Defined in CMSCommon.h 
       switch (acc) 
       { 
         case Malloc: 
           printf("malloc\n"); 
           break; 
         case Calloc: 
           printf("calloc\n"); 
           break; 
         case Realloc: 
           printf("realloc\n"); 
           break; 
         case Strdup: 
           printf("strdup\n"); 
           break; 
         #ifdef WIN32 
           case Wcsdup: 
             printf("wcsdup\n"); 
             break; 
           case Mbsdup: 
             printf("mbsdup\n"); 
             break; 
           case Globalalloc: 
             printf("GlobalAlloc\n"); 
             break; 
           case Localalloc: 
             printf("LocalAlloc\n"); 
             break; 
           case Heapalloc: 
             printf("HeapAlloc\n"); 
             break; 
           case Heaprealloc: 
             printf("HeapRealloc\n"); 
             break; 
         #else 
           case Valloc: 
             printf("valloc\n"); 
             break; 
           case Memalign: 
             printf("memalign\n"); 
             break; 
         #endif 
         default: 
           printf("Unknown type\n"); // Could "never" happen :-) 
           break; 
       } 
     
       printf("Memory (B) = %d\n", (*cmsData).size); 
       printf("Thread Id  = %d\n", (*cmsData).threadId); 
       printf("Index      = %d\n", (*cmsData).index); 
       printf("Pointer    = %p\n", (*cmsData).ptr); 
       printf("---------------------\n"); 
       cmsData = CMemScavGetListEntry(EntryNext); // Get next (or prev with EntryPrev) 
     } 
     CMemScavGetListEntry(EntryFinish); // Release the mutex locking the list 
     CMemScavShowList(); // Show the same info with CMemScav 
     printf("Compare the list above with the Monitor's list view.\n"); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     CMemScavFreeAll(); // (clean up before next demo) 
     
     // ******************************************************************* 
     printf("How to use the Monitor's Synthesize view to create calls\n"); 
     printf("to CMemScavFreeThese and CMemScavFreeAll functions\n"); 
     printf("--------------------------------------------------------\n"); 
     // ******************************************************************* 
     printf("First we allocate some memory, both by calling the blackBox function\n"); 
     printf("as well as running the threadFunc function in %d threads.\n", NO_THREADS); 
     printf("The result is displayed in the Monitor by calling CMemScavShowList.\n"); 
     blackBox(); 
     for (n = 0; n < NO_THREADS; n++) 
     { 
       #ifdef WIN32 
         tHandles[n] = CreateThread(NULL, 0, threadFunc, &idx[n], 0, &threadId[n]); 
       #else 
         pthread_create(&threadId[n], NULL, threadFunc, &idx[n]); 
       #endif 
     } 
     
     // Wait for the threads to finish 
     // - - - - - - - - - - - - - - - 
     for (n = 0; n < NO_THREADS; n++) 
     { 
       #ifdef WIN32 
         WaitForSingleObject(tHandles[n], INFINITE); 
       #else 
         pthread_join(threadId[n], NULL); 
       #endif 
     } 
     CMemScavShowList(); 
     printf("Now, hit the \"Generate 'C Memory Scavenger' code\" button, the one\n"); 
     printf("with a Notebook, Hand, and a Pencil on it, in the Synthesize view\n"); 
     printf("(or in the tool bar). Try different adustments by changing the\n"); 
     printf("checkboxes, radio buttons, and text fields in this view, and click \n"); 
     printf("the button again, to see how calls to CMemScavFreeThese are generated.\n\n"); 
     printf("These calls may be written to file using the \"Save code on file\"\n"); 
     printf("button (for later copy/paste into the source code), where each line\n"); 
     printf("may be indented with a fixed number of spaces or tabs.\n"); 
     printf("Line breaks will be of Windows style <CR><LF>, if the\n"); 
     printf("application is running on Windows, or Unix style <CR> otherwise.\n"); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     
     // ******************************************************************* 
     printf("How to free specific pointers from the Monitor\n"); 
     printf("----------------------------------------------\n"); 
     // ******************************************************************* 
     printf("Instead of calling CMemScav functions to free some or all\n"); 
     printf("outstanding allocations, these may be freed directly from\n"); 
     printf("the Monitor. To do so, first pause this application by\n"); 
     printf("clicking the 'Pause the application'-button, then get a\n"); 
     printf("fresh list by clicking the 'Get list of allocations'-button.\n"); 
     printf("Now the button looking like a dustbin/trash can is enabled.\n"); 
     printf("Clicking this button will free ALL pointers. If you select\n"); 
     printf("some lines in the list before clicking this button, only\n"); 
     printf("the slected pointers will be freed.\n\n"); 
     printf("Try this and update the list to see the new status.\n"); 
     printf("Don't forget to release the application when finished\n"); 
     printf("(the \"Play\"-button to the right of the \"Pause\"-button).\n"); 
     printf("Hit ENTER to go on...\n"); 
     getchar(); 
     printf("\n"); 
     printf("This will end the Advanced Demo. You may exit this program\n"); 
     printf("without loosing the data in the Monitor.\n"); 
     printf("Hit ENTER when ready to exit this application...\n"); 
     getchar(); 
     
     // Close CMemScav 
     // -------------- 
     CMemScavFreeAll(); // Make sure this demo is not leaking memory, 
     CMemScavFinish();  // wouldn't be nice, would it? 
    //  CMemScavShowList(); // Any calls to CMemScav functions, except CMemScavInit(), 
                           // after CMemScavFinish() has been called, gives 
                           // unpredictable behaivour and should be avoided. 
     return 0; 
     
    #ifdef __cplusplus 
     } 
    #endif 
     
    Code List of DemoFunction.c 
     
    #ifndef WIN32 
     #include <stdlib.h> 
    #endif 
    #include "CMemScav.h" 
     
    /* All in C */ 
    #ifdef __cplusplus 
     extern "C" 
     { 
    #endif 
     
    /******************************************************************** 
    * Definition of local function to be called from main() 
    *******************************************************************/ 
    void blackBox() 
     // Allocate some memory without taking care of the addresses 
     malloc(rand()+1); 
     calloc(1, rand()+1); 
     malloc(rand()+1); 
     
    #ifdef __cplusplus 
     } 
    #endif