#include <cstdio>
#include <cstring>
#include <crtdbg.h>
#include <malloc.h>
#include <windows.h>

void printMemory( void* ptr_, int size )
{
	unsigned char* ptr = (unsigned char*)ptr_;

	for( int i=0; i < size; )
	{
		std::printf( "0x%.8p ", ptr + i );
		for( int j=0; j < 16 && i < size; j++, i++ )
		{
			std::printf( "%.2x", ptr[i] );
		}
		
		std::printf( "\n" );
	}
}

void doNormalNew( const int size )
{
	std::printf( "\nNormal new:\n" );
	char* buffer = new char[size];	
	
	printMemory(buffer - 16, 16);
	printMemory(buffer,size);
	printMemory(buffer + size, 16);
	delete[] buffer;
}

void doHeapAlloc( const int size )
{
	void* bogus = HeapAlloc(GetProcessHeap(), 0, 4);
	std::printf( "\nBogus heap ptr=%p\n", bogus );
	
	std::printf( "\nHeapAlloc:\n" );
	char* buffer = (char*)HeapAlloc(GetProcessHeap(), 0, size);
	
	printMemory(buffer - 16, 16);
	printMemory(buffer,size);
	printMemory(buffer + size, 16);
	
	std::memset(buffer,0,size);
	HeapFree(GetProcessHeap(), 0, buffer);

	std::printf( "\nHeapFree:\n" );
	printMemory(buffer - 16, 16);
	printMemory(buffer,size);
	printMemory(buffer + size, 16);
	
	
	HeapFree(GetProcessHeap(), 0, bogus);

}

void doNormalMalloc( const int size )
{
	std::printf( "\nNormal malloc:\n" );
	char* buffer = (char*)malloc(size);
	printMemory(buffer - 16, 16);
	printMemory(buffer,size);
	printMemory(buffer + size, 16);
	free(buffer);
}

void doStackMemory()
{
	std::printf( "\nStack memory:\n" );
	char buffer[16];
	printMemory(buffer,sizeof(buffer));
}

void doFreeCppMemory( const int size )
{
	std::printf( "\nFree memory:\n" );
	char* buffer = new char[size];	
	delete[] buffer;
	printMemory(buffer - 16, 16);
	printMemory(buffer,size);
	printMemory(buffer + size, 16);
}

void doFreeMallocMemory( const int size )
{
	std::printf( "\nFree malloced memory:\n" );
	char* buffer = (char*)malloc(size);
	free(buffer);
	printMemory(buffer - 16, 16);
	printMemory(buffer,size);
	printMemory(buffer + size, 16);
}

void doMemoryLeakCheck()
{
	std::printf( "\nCheckpoints\n" );
	
	if( 0 == _CrtCheckMemory() )
		std::printf( "Failed checkpoint 1\n" );
	
	char* buffer = new char[4];	
	
	const char old = buffer[5];
	
	buffer[5] = 1;

	if( 0 == _CrtCheckMemory() )
		std::printf( "Failed checkpoint 2\n" );
		
	buffer[5] = old;
	
	delete[] buffer;
}

void detectMemoryLeaks()
{
	char* buffer = new char[13];
	_CrtMemDumpAllObjectsSince(0);
}

void doDoubleDelete()
{
	char* buffer = new char[3];
	delete[] buffer;
	delete[] buffer;
}


int main( int, char** )
{
	doHeapAlloc(15);
	
	doNormalNew(16);
	doNormalMalloc(16);
	doStackMemory();

	doFreeCppMemory(16);
	doFreeMallocMemory(16);

	doMemoryLeakCheck();
	detectMemoryLeaks();
	
	return 0;
}


