Sign in to follow this  

storing an instance of a class in an array

This topic is 3855 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi there. Ive posted before about somehing like this and was given an answer bt didnt really understand why this was happening. Ive just started to mess around with c++ again and come accross the same problem. Here is what ive done
	cEnemy * pEnemyArray = new cEnemy[2];
	cEnemy * a = new cEnemy;
	
	a		= NULL;
	pEnemyArray = NULL;
	peArray[0].SetName("SET NAME");

	delete a;
	delete [] pEnemyArray;


	//self checks
	if((a && pEnemyArray)== NULL)
	{
		cout << "pointers are NULL" << endl;
	}else
	{
		cout << "pointers are not null" <<endl;
	}


everything in the classes are working fine but i just cant sem to make an instance of a class eg Enemy 1 and then store this enemy in an array so later can pull this enemy out and have my player attack it. i keep getting a debugger error and a message saying system.NullreferenceException Object reference not set to an instance of an object. If you know why this is happenin can you explain it to me so i understand the fundamentals. If its just totally wrong someone please show and explain, i seriously have some trouble when trying to do this and i cant seem to research why im making this mistake. Ive done something like his in the past and didnt have this error . . bu then again ive not programmed for ages now and it may be something simple that i am overlooking. Thanks

Share this post


Link to post
Share on other sites
I honestly can't really understand what you're trying to do by looking at the code. Just going by this:

Quote:

but i just cant sem to make an instance of a class eg Enemy 1 and then store this enemy in an array so later can pull this enemy out and have my player attack it.


I assume you need to store the enemy in an array of *pointers*:

CEnemy** pEnemyArray=new cEnemy*[2];
CEnemy* a=new CEnemy;

pEnemyArray[0]=a;

or better yet, use vectors.

Share this post


Link to post
Share on other sites
so the double * is the answer

all im trying to do is make an enemy . . or an instance of 1 using my enemy class and stick it in an array. the array will hold say 5 enemys, when i kill ot i delete it from the array or FILO it and push it back on with increased stats (of course when i make my dynamic list, atm i just want to use a static array so i know for now exactly what bits got in it)

yes vectors are in my plan but when i hit this i really need to sort it out

so . . the double ** whats that mean then and why does that make it work (havent checked it yet tho)

Share this post


Link to post
Share on other sites
Maybe a simple example will help.

First of all, a pointer is a variable designed to hold the address of another variable.

int* pInts[2]; // This is an array of 2 pointers to int.
int* pInt; // This is a pointer to int.

At this point all three pointers are uninitialized.
In other words they contain random addresses so to speak.
If we try to do anything with what they point to the program will typically crash.

pInt = new int;

The new keyword will ask the OS to find a free slot in memory and return the address of that slot back to our program. We catch that address in pInt.

Now pInt contain a valid address that we can do things to.
For example we can put the number 1 in that slot:
*pInt = 1;

We can copy that valid address into the first array element:
pInts[0] = pInt;

Now, pInts[0] contains the same valid address as pInt, and they can both be used to do things to our memory slot.

Then we put the address 0 into pInt:
pInt = NULL; // This does not change what pInt points to, it changes where pInt points!

Now pInt holds the address 0. 0 is not a valid address and if we try to do anything to what it points to, the program will probably crash again.
However, pInts[0] still holds our valid address, so we can still use that.

*pInts[0] = 2;

Now if we put address 0 into pInts[0]:
pInts[0] = 0; // Or NULL

Now both our pointers point to memory address 0 and they are both invalid.
At this point we have what is called a memory leak!
This is becouse we have lost the address that the OS gave us earlier, and there is no way for us to find out what it was.
As you probably understand a memory leak is a bad thing =)


Lets say we have a int variable called i:
int i;

If we want pInt to point to i's memory address we do:
pInt = &i;
If we do anything to what pInt points to now, we actually change i itself.
*pInt = 3;

One thing you do in your code is to delete a pointer that points to address 0.
This will again crash our program.

Does this make sense?

Share this post


Link to post
Share on other sites

//self checks
if((a && pEnemyArray)== NULL)
{
cout << "pointers are NULL" << endl;
}
else
{
cout << "pointers are not null" <<endl;
}



I doubt this is what you want to do.
If you want to make sure all the pointers is pointing at address 0
you must test all pointers separately:

//self checks
if(a == NULL && pEnemyArray[0] == NULL && pEnemyArray[1] == NULL)
{
cout << "pointers are NULL" << endl;
}
else
{
cout << "pointers are not null" <<endl;
}


Share this post


Link to post
Share on other sites
even that last one isn't quite right for making sure there are NO nulls going to be used, it needs to be

if(pointerA == 0 || pointerB == 0 || ...)
// some pointer is null
else
// no null pointers, do what you want safely now.

also, I recommend using something like:

typedef std::vector<cEnemy*> EnemyList;

then you get much cleaner syntax for allocation and size changes than with dynamic arrays, std::vector is a much easier class to use than dynamic arrays, ESPECIALLY if you get into multidimentional dynamic arrays.

and with vectors its easy to tell what levels are lists of things, and what levels are pointers and what levels are not.

using namespace std;
vector<cEnemy*>; // a list of enemies (using pointers)
vector<cEnemy>; // a list of enemies, not using pointers (not very usefull)

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
even that last one isn't quite right for making sure there are NO nulls going to be used, it needs to be

if(pointerA == 0 || pointerB == 0 || ...)
// some pointer is null
else
// no null pointers, do what you want safely now.


... Because of this, the original snippet actually works, though sort of accidentally.

(Hint: consider deMorgan's laws.)

Quote:

also, I recommend using something like:

typedef std::vector<cEnemy*> EnemyList;


Yes. Although I prefer to use the word 'Container' (thus EnemyContainer) for such typedefs, in order to speak more abstractly about what is actually there (i.e. not create an impression that std::list is being used).

Quote:
then you get much cleaner syntax for allocation and size changes than with dynamic arrays, std::vector is a much easier class to use than dynamic arrays, ESPECIALLY if you get into multidimentional dynamic arrays.


Actually, multidimensional, rectangular dynamic arrays are better done with boost::multi_array. :)

Quote:
vector<cEnemy>; // a list of enemies, not using pointers (not very usefull)


Disagreed. In simple cases (i.e. the class is default/copy-constructible, assignable and not polymorphic; and we are not sharing enemies between containers), holding them by value is just as useful, significantly simpler, highly likely to be better-performing, and more space-efficient.

Also, please ask yourself what the leading 'c' on the class name is telling that you don't already know (either from *looking* at the code, or from what your IDE and/or compiler can tell you). Is it worth the extra effort and ugliness?

Share this post


Link to post
Share on other sites
Quote:
Original post by DrPepperCornso . . the double ** whats that mean then and why does that make it work (havent checked it yet tho)


Because it's a pointer to a pointer(s) :)

You're initialising a pointer to an array object, which is holding pointers to your game objects.

Share this post


Link to post
Share on other sites
I may have misunderstood the point, but I interpreted the orignal code:

if(a & b == null)

as a somewhat improper attempt to test if ANY of the pointers is null, not a test to see if ALL the pointers are null (which is closer to what it actually does - but of course it doesnt do it correctly).

I may have been wrong, it was just an assumption on my part, because normally when I'm checking a set of pointers for null, its cause I want to know if they are safe to use, to run some algorithm that can't handle null, like

if(a != 0 || b != 0)
a[i] = b[i];

or some such

so if the person wants

if()
// some pointer is null
else
// no pointer is null

my code is correct

and if they want

if()
// all pointers are null
else
// some pointer is not null

pulpfist's code is correct

the complication isn't with demorgan's law, but intent of the code.

Share this post


Link to post
Share on other sites
woah. thanks guys, the error checking bit i did just as an after effect to check that my pointers were init to NULL, in fact at this point that was just old code.

Great stuff, i can always count on this site to clear one or two things up, just gonna plod now and may post back here if i un into any problems, saves me creating 50 topics here there and every where

Share this post


Link to post
Share on other sites
accessing an item in a vector is the same as an array, you can use the subscript opertor:

enemies[0]->Attack(player); // or some such.

or you can use an iterator


typedef std::vector<cEnemy*> EnemyList;
for(EnemyList::iterator currentEnemy = enemies.begin(); currentEnemy != enemies.end(); ++currentEnemy)
{
currentEnemy->Attack(player);
}


now of course, if you need to find the enemy named dog its got to be something a little trickier, like:


typedef std::vector<cEnemy*> EnemyList;
for(EnemyList::iterator currentEnemy = enemies.begin(); currentEnemy != enemies.end(); ++currentEnemy)
{
if(currentEnemy->Name == "Dog")
{
currentEnemy->Attack(player);
break;
}
}


there are many cooler more advanced things you can learn to do, to perform this type of action easier, but these should get you started.

truthfully, you normally don't "look through the list for an enemy named dog to attack the player", you normally have lists, such as

EnemyList enemies;

and you do stuff like loop though all enemies to let them do whatever they are doing.


typedef std::vector<cEnemy*> EnemyList;
for(EnemyList::iterator currentEnemy = enemies.begin(); currentEnemy != enemies.end(); ++currentEnemy)
{
currentEnemy->PerformAction(); // attacks if attacking, defends, runs, whatever
}


Share this post


Link to post
Share on other sites

This topic is 3855 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this