Help!! Pointer Assignment!

Hey guys,

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;
	}
}


Here is my retrieve();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool HashTable::retrieve(char const * 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;
			return true;
		}
		else
			curr = curr->next;
	}

	//data is not in the table
	return false;
}


Here is my Player.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#ifndef PLAYER_H
#define PLAYER_H

#include <iostream>
using namespace std;

enum GType {UNKNOWN, MALE, FEMALE};

class Player
{
private:
	char* name;
	GType gender;
	int level;

public:
	Player();
	Player(char* nm, GType type);
	//~Player();

	void SetName(char* nm);
	void SetLevel(int lvl);
	void SetType(GType type);

	char* GetName()const ;
	void GetName(char* nm)const ;
	int GetLevel()const ;
	GType GetGenderType();

	void LevelUp();

	const Player& operator=(const Player& aPlayer);	 //overloading assignment operator
	friend ostream& operator<<(ostream& out, const Player& aPlayer);
	char* GenderTypeString(GType type);
};

#endif 


And here is my LevelUp();
1
2
3
4
void Player::LevelUp()
{
	level += 1;
}


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();

Any help will be appreciated.

Thank you.
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.

Jim
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.

Any thoughts?

Thank you.
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)

Jim
So I'd need to dynamically allocate info in the FetchPlayer();?
I'm sorry, I'm a bit confused and a beginner in c++.

Thanks again.
Yes, your FetchPlayer() needs to be:

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 = 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.

Jim
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();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}
You're not updating the hash-table's entry, you're updating the temporary local Player info declared in FetchPlayer().

Jim
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.

I'm sorry if I'm not being clear.
Thanks.

Matheus.
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.

Jim
Topic archived. No new replies allowed.