Skip to main content
gamedev.net
🔒 Locked

Pointer problem...I think

Started by Nomad010 Dec 19, 2004 at 1:08 PM 2 replies 850+ views
Original Post
Nomad010
Nomad010
I was programming the skeleton of a Direct Draw game. I decided to use a queue DS instead of acting on them immediately. However, I think I must have screwed up on one of the pointers because now I get error on calling one of the methods I will post the entirety of the code here, but the real problem occurs only when you press down a key. Main.cpp

#define WIN32_LEAN_AND_MEAN

#include "windows.h"
#include "windowsx.h"
#include "stdio.h"
#include "conio.h"

#include "CKeyQueue.h"
#include "CKeyQueueItem.h"
#include "CKeyStroke.h"


HWND hWnd; //handle to our window
HINSTANCE hInst; //handle to application instance
bool gameActive; //is the game active
CKeyQueue *keyQueue; //our keys are held in a queue.

//CKeyStroke* k = NULL;


LRESULT CALLBACK MsgHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
BOOL Initialise_Game();
void Game_Loop();

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow)) 
	{
		return FALSE;
	}

    Game_Loop();

	return 0;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX sampleClass;

	sampleClass.cbSize = sizeof(WNDCLASSEX);
	sampleClass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	sampleClass.lpfnWndProc = MsgHandler;
	sampleClass.cbClsExtra = 0;
	sampleClass.cbWndExtra = 0;
	sampleClass.hInstance = hInstance;
	sampleClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
	sampleClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	sampleClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
	sampleClass.lpszMenuName = NULL;
	sampleClass.lpszClassName = "Sample Class";
	sampleClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

	return RegisterClassEx(&sampleClass);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;

    hInst = hInstance; // Store instance handle in our global variable

	hWnd = CreateWindow("Sample Class", "Sample Window", WS_POPUP | WS_VISIBLE,
       (1152-640)/2, (864-480)/2, 640, 480, NULL, NULL, hInstance, NULL);

    if (!hWnd)
     return FALSE;
   
    //ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

LRESULT CALLBACK MsgHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    if (msg == WM_CREATE)
    {
		if(!Initialise_Game())
			MessageBox(hWnd,"Error","Error",0);
        return(0);
    }

	if (msg ==  WM_KEYDOWN)
	{
		keyQueue->add(new CKeyStroke((unsigned int) wparam));	
	}

    return(DefWindowProc(hwnd, msg, wparam, lparam));
}

BOOL Initialise_Game()
{
 gameActive = true;

 keyQueue = new CKeyQueue();

 if(!keyQueue)
	 return FALSE;

 return TRUE;
}

void Game_Loop()
{
	MSG msg;

	while (gameActive) 
	{
		//Process Messages
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		//Update Screen

		//Perform Game Logic
		if(keyQueue->keysWaiting())
		{
			keyQueue->pop();
		}
	}
}

CKeyQueue.h

#pragma once
#include "CKeyQueueItem.h"
#include "CKeyStroke.h"

class CKeyQueue
{
private:
	CKeyQueueItem *firstItem;
	CKeyQueueItem *lastItem;

public:
	CKeyQueue();
	~CKeyQueue();
	void add(CKeyStroke *item);
	CKeyStroke pop();
	CKeyQueueItem* getFirstItem() { return firstItem; };
	void setFirstItem(CKeyQueueItem* newFirstItem) { firstItem = newFirstItem; };
	CKeyQueueItem* getLastItem() { return lastItem; };
	void setLastItem(CKeyQueueItem* newLastItem) { lastItem = newLastItem; };
	bool keysWaiting();
};

CKeyQueue.cpp

#include "CKeyQueue.h"
#include "CKeyQueueItem.h"
#include "CKeyStroke.h"

CKeyQueue::CKeyQueue()
{

	firstItem = 0;
	lastItem = 0;
}

CKeyQueue::~CKeyQueue()
{
	CKeyQueueItem* currentItem = lastItem;

	while(!currentItem->getIsFirst())
	{
		if(currentItem->getNextItem())
         delete currentItem->getNextItem();

		currentItem = currentItem->getPrevItem();

	}

}

void CKeyQueue::add(CKeyStroke *item)
{

	if(!item)
		return;

	if(!firstItem)
	{
		firstItem = new CKeyQueueItem(item);
		lastItem = firstItem;
	}
	else
	{
		lastItem->setNextItem(new CKeyQueueItem(item));
		lastItem->getNextItem()->setPrevItem(lastItem);
		lastItem->setIsLast(false);
		lastItem = lastItem->getNextItem();
		lastItem->setIsFirst(false);
	}

}

CKeyStroke CKeyQueue::pop()
{
	if(!firstItem)
		return 0;
	
	while(!firstItem->getCurrent()->isValid())
	{
		firstItem = firstItem->getNextItem();
		delete firstItem->getPrevItem();
	}

	CKeyStroke temp = *(firstItem->getCurrent());

	delete firstItem;

	return temp;
}

bool CKeyQueue::keysWaiting()
{
	return !(firstItem == 0); //0 = NULL
}

CKeyQueueItem.h

#pragma once
#include "CKeyStroke.h"

class CKeyQueueItem
{
private:
    CKeyQueueItem *prevItem;
	CKeyQueueItem *nextItem;
	CKeyStroke *current; 
	bool isFirst;
	bool isLast;

public:
	CKeyQueueItem(CKeyStroke* item);
	~CKeyQueueItem();
	CKeyQueueItem* getPrevItem() { return prevItem;};
	void setPrevItem(CKeyQueueItem* newPrevItem) { prevItem = newPrevItem; };
	CKeyQueueItem* getNextItem() { return nextItem;};
	void setNextItem(CKeyQueueItem* newNextItem) { nextItem = newNextItem; };
	bool getIsFirst() { return isFirst; };
	void setIsFirst(bool newIsFirst) { isFirst = newIsFirst; };
	bool getIsLast() { return isLast; };
	void setIsLast(bool newIsLast) { isLast = newIsLast; };
	CKeyStroke* getCurrent() { return current; };
	void setCurrent(CKeyStroke* newCurrent) {current = newCurrent;};
};

CKeyQueueItem.cpp

#include "CKeyQueueItem.h"
#include "CKeyStroke.h"

CKeyQueueItem::CKeyQueueItem(CKeyStroke *item)
{
	prevItem = 0;
	nextItem = 0;
	current = item;
	isFirst = true;
	isLast = true;
}

CKeyQueueItem::~CKeyQueueItem()
{
	delete current;
}


CKeyStroke.h

#pragma once

class CKeyStroke
{
private:
	unsigned int keyPress;
	__int64 secondsTime;
	unsigned int millisTime;

public:
	const static unsigned int TIMEOUT = 60000;
	CKeyStroke(unsigned int key);
	~CKeyStroke();
	unsigned __int64 getKeyPress(){return keyPress;};
	bool isValid();
};

CKeyStroke.cpp


#include "CKeyStroke.h"
#include <sys/timeb.h>
#include <time.h>


CKeyStroke::CKeyStroke(unsigned int key)
{
	keyPress = key;
	struct __timeb64 timebuffer;
	_ftime64( &timebuffer );

	secondsTime = timebuffer.time;
	millisTime = timebuffer.millitm;
}

CKeyStroke::~CKeyStroke()
{
}

bool CKeyStroke::isValid()
{
	struct __timeb64 timebuffer;
	_ftime64( &timebuffer );

	return ((timebuffer.time - secondsTime) * 1000 + (millisTime - timebuffer.millitm)) > TIMEOUT;
}

Here is the run-time error message: Unhandled exception at 0x00412406 in TileGame.exe: 0xC0000005: Access violation reading location 0x00000000. The current line of code is: CKeyQueueItem* getPrevItem() { return prevItem;}; This leads me to suspect a pointer error somewhere. I've tried to look for it, but to no avail. Thanks in advance.
"..."
Enigma
Enigma
You don't seem to actually call Initialise_Game() anywhere, so keyQueue is never initialised.

Why have you written your own queue class instead of just using the std::queue adaptor?

Enigma
nimrand
nimrand
Just so you know, STL provides very nice queue/stack/list classes, but its also good practice to write your own. I think I may have found your problem:

CKeyStroke CKeyQueue::pop(){	if(!firstItem)		return 0;		while(!firstItem->getCurrent()->isValid())	{		firstItem = firstItem->getNextItem();		delete firstItem->getPrevItem();	}	CKeyStroke temp = *(firstItem->getCurrent());	delete firstItem;	return temp;}


In your while loop, you set firstItem to firstItem->GetNextItem(). But, if you have reached the end of your list, firstItem's new value will be NULL (right?). Then, on the next line you call delete firstItem->getPrevItem(). Calling firstItem->getPrevItem() when firstItem is NULL will cause a memory access violation because getPrevItem will try to access member variables that don't exist.

EDIT: I realized I wasn't as clear as I could have been. Hopefully it is clear now.

[Edited by - nimrand on December 19, 2004 1:33:18 PM]
Nomad010
Nomad010
No. The Enigma's answer is wrong. Game_Initialise() is called on WM_CREATE.

Also, to answer your question.

Quote:

Why have you written your own queue class instead of just using the std::queue adaptor?


Answer

Quote:

STL provides very nice queue/stack/list classes, but its also good practice to write your own.


I don't think the other answer is right either. I don't think the while loop is the problem either as it should never run except for a really big key list, but you did make the error visible to me.

Epiphony: The isValid() method has the wrong sign.

Thanks for your posts.(darn sign)
"..."

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.