My LevelUp function is not working. I explain more after my code. Here is the code.
The LevelUp(); call:
1 2 3 4 5 6 7
Player* outPlayer = NULL;
// Test 5: Fetch a player and make sure that it is the correct one
outPlayer = pdb.FetchPlayer("Sappho");
if (outPlayer != NULL) {
outPlayer->LevelUp();
}
Here is my FetchPlayer();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Player* PlayerDB::FetchPlayer(char* name)
{
Player info;
out << "Fetching player " << "\"" << name << "\" -- ";
if(h.retrieve(name, info))
{
out << "Success!" << endl;
Player *temp = &info;
return temp;
}
else
{
out << "Failed." << endl;
return NULL;
}
}
bool HashTable::retrieve(charconst * const key, Player& aPlayer)const
{
//calculate the retrieval position (the index of the array)
size_t index = calculateIndex(key);
//search for the data in the chain (linked list)
node * curr = table[index];
char id[100];
while (curr)
{
curr->item.GetName(id);
if(strcmp(key, id) == 0)
{
//find match and return the data
aPlayer = curr->item;
returntrue;
}
else
curr = curr->next;
}
//data is not in the table
returnfalse;
}
When the FetchPlayer() returns the pointer it passes that pointer to outPlayer and after I debugged it, it has the correct class object to level up. After outPlayer calls LevelUp(); is where my data gets corrupted. The name of the Player changes and the gender and level of the player changes to the same big negative number, but the level for the player in the database continues to be the default one, 0. So I think it is just never accessing the Player instance.
I believe I'm just not assigning the pointer correctly in my FetchPlayer();
FetchPlayer() is declaring a local Player info and you're returning a pointer to it. Outside of FetchPlayer, info doesn't exist so the pointer you're returning is pointing to invalid memory.
It seems to be sort of working now. I checked the level of the player before the LevelUp call and after and the result is 0(before call) and 1(after call), which is exactly right.
For some reason it doesn't seems to actually be storing the value for that player. When I output my table, it still says level 0 even after the LevelUp call.
That's the nature of memory leaks and invalid pointers - sometimes you'll be lucky and it'll work, others it will get wrong values, others still it will fall in a steaming heap.
What's happening is the memory used for your local Player info variable within FetchPlayer() is sometimes (once the function returns) being re-used for other storage and sometimes not.
If it's re-used, it'll have new bytes stamped over it and you'll get invalid data.
If it's not re-used, you're lucky and your values will still be there. You still shouldn't be accessing it though because it's no longer allocated.
If you want to return a pointer to a Player you have to dynamically allocate that Player object (and make sure you delete it when you're done)
Player* PlayerDB::FetchPlayer(char* name)
{
Player* info = new Player();
out << "Fetching player " << "\"" << name << "\" -- ";
if(h.retrieve(name, *info))
{
out << "Success!" << endl;
return info;
}
else
{
out << "Failed." << endl;
delete info;
return NULL;
}
}
Or similar (I haven't tested the above)
And then make sure you delete the outPlayer pointer when you're done.
Keep in mind though, you're now mixing Player pointers in the PlayerDB class and Player references in the HashTable class. While these are interchangeable and can be directly converted, it would be better to use one or the other all the way through, for simplicity's sake.
This is so weird to me. It does work because I tested the level value before and after the LevelUp call, but when I call my output to screen function, PrintDiagnostics(); the value for that Player instance is still 0. Here is my PrintDiagnostics();
ostream& operator<<(ostream& out, HashTable& ht)
{
int i;
HashTable::node * curr;
for(i=0; i < ht.capacity; i++)
{
out << "Slot [" << i << "]:" << endl;
if(ht.table[i] == NULL)
{
out << " EMPTY" << endl;
}
else
{
for(curr = ht.table[i]; curr; curr = curr->next)
//we can use << on data object because we overload << in the data class
out << " " << curr->item;
}
}
return out;
}
Okay, but what I'm trying to do here is to update the Player instanced searched. So what you are saying is that I'm only updating a temporary value of some sort and not the actual Player object in the Hash Table?
If that is true, then I'd have to remove the Player instance and then insert it again with an updated value, or is there a way to update the level value of a Player instance inside the Hash Table.
From what I can see, your HashTable::retrieve() method needs to change; at the moment it's returning a copy, copied to the aPlayer reference. You need to return a reference to the object, or a pointer to it.
You've also marked HashTable::retrieve() as 'const', which means you can't return anything that can be used to alter the content anyway. You'll need to remove that const tag.
Sorry, I'm a bit pressed for time at the moment so I can't go into too much detail.