...

View Full Version : Resolved How to pass arrays of objects to function in c++?



SirSkorpan
08-28-2009, 06:49 PM
Hi!

I'm fairly new to this whole programming business but I'm getting there... slowly :D

What I'm trying to do is to send an array of objects to a function and have this function access one of the objects memberfunctions. This is pretty much what I have (I've cut away some code so it'll be easier to follow and some stuff thats not finished).

I've highlighted the portions where I think I got things wrong but don't know what.

in header file GameHost.h




#include "Die.h" // forward declaration of class Die
#include "GameIO.h" // forward declaration of class GameIO


/**
* class GameHost starts a round of dice, is responsible for letting
* the player roll his/her dice and keeping track on when the round is over
* and more...
**/
class GameHost
{
public:
GameHost(); // constructor for Game host class
~GameHost(); // destructor for Game host class -- preforms house keeping, cleans allocated memory

int startRound(); // Starts round of the game

void rollDice(); // rolls all dice the player has and calls the choose Dice
// function if appropriate
void rollDice( int diceToRoll[] ); // Overloaded version of rollDice which
// takes an array specifying which dice to roll

void chooseDice(); // lets the player choose which die/dice if any to roll

void endRound(); // Ends the round and resets members for a new round

static const int nDice = 5; //contains the number of dice in the game


private:
Die* Dice; // creates an array with five (5) Die objects
// is there a problem with my declaration of the array with Die objects?

GameIO myIO; // creates a I/O object

int numberOfRolls; // keeps track of number of rolls during the round
int rollsInRound; // decides how many rolls there should be in a round
// (including first roll and x number of re-rolls)

int* chooseDie( int nReroll ); // support function that prompts the user to
// choose a die to re-roll,
// takes the number of dice to re-roll as
// argument and returns an array with the
// chosen dice

}; // end class GameHost


in cpp-file GameHost.cpp:



/**
* constructor for Game Host class - initializing array Dice
**/
GameHost::GameHost()
{
// Dice contains an array with pointers to Die objects
Dice = new Die[ nDice ]; // create space in memory for an array of Die objects
// should I initialize this in a different manner? Is there an other way?

rollsInRound = 3; // decides how many rolls there should be in a round (including first roll and x number of re-rolls)

numberOfRolls = 0; // initialize numberOfRolls to 0

} // end constructor GameHost


/**
* destructor for Game Host class - preforms housekeeping and cleans allocated memory resources
**/
GameHost::~GameHost()
{
delete [] Dice; // give back memory space occupied by array of Die objects - Dice

} // end destructor GameHost


/**
* startRound() starts a round of dice by rolling all dice (through rollDice)
**/
int GameHost::startRound()
{
rollDice(); // start of round by rolling dice

return 0; // when round ends startRound return 0 to caller

} // end startRound


/**
* rollDice rolls all the dice and prints them for user then decides whether to continue round or end it.
**/
void GameHost::rollDice()
{

// loop through the dice in array Dice and roll each once
for ( int i = 0; i < nDice; i++ )
{
Dice[ i ].rollDie(); // roll the dice in array Dice by
// using the Die objects member function rollDie()
// this stores a value between 1-6 in the die object


}

// print the dice through the gameIO
myIO.printDice( &Dice, nDice );
/** this call is where things starts to go wrong
* I believe it's correct to send it like that??
* I've also tried sending it by value without '&' but then
* the compiler won't recognize the call (but I guess thats
* because I've written it the way I have).
**/

numberOfRolls++; // increment numberOfRolls since dice have been rolled and printed

// if player have rolled three times (first roll and two rerolls)
if ( numberOfRolls == rollsInRound )
{
endRound(); // end round

}
else
{
chooseDice(); // choose which die/dice to reroll next

}

} // end rollDice


/**
* endRound() ends the round of dice and resets the numberOfRolls so
* game host is ready for a new round
**/
void GameHost::endRound()
{
numberOfRolls = 0; // Reset number of Rolls

} // end endRound


in header-file GameIO.h



#include <string>
using namespace std;

#include "Die.h"


// handles input and output in a game of Dice
class GameIO
{
public:
GameIO ();
// Overloading function printText -- one for char and one for strings

void printText( const string& stringPtr); // Receives a reference to a string.
// Prints it without touching it.
void printText( const char* stringPtr); // Receives pointer to a character
// string. Prints it without
// modifications.

void printInt( const int& intPtr); // takes a reference to an int and prints it.

// printDice takes an array of pointers to Die objects
// and prints a line of die illustrations with eyes corresponding to the
// values gathered from the dice.
// Also takes the number of dice as argument as an int
void printDice( Die* diceArray[], const int numberOfDice );

// this is the problematic function

void printColumns( int nCols ); // prints new lines and tabs in a sequence
// allowing for output of text in columns
// takes an int (representing the number of
// columns) as argument

int getInt(); // fetches int from user and sends it back to caller, also
// checks if data input is really int

private:
int columnCounter; // helps printColumns to know where columns and
// newlines starts
};

in cpp-file gameIO.cpp


#include <iostream>
using namespace std;

#include "GameIO.h"

/**
* Constructor for game I/O
**/

GameIO::GameIO()
{
columnCounter = 1; // initialize columnCounter
}

/**
* printDice takes an array of ints (with each element in the array representing
* the faces of the dice to be printed) and an int (representing the number of dice)
* as arguments and prints a row of dice corresponding to the ints received.
* Se exampel below.
**/

/****************************************
* --::EXAMPLE::--
* output from printDice
* ------- ------- ------- ------- -------
* | | | * | | * | | * * | | * * |
* | * | | | | * | | | | * |
* | | | * | | * | | * * | | * * |
* ------- ------- ------- ------- -------
*
******************************************/
void GameIO::printDice( Die* diceArray[], const int numberOfDice )
{
// this function is the problem !!

int diceToPrint[ numberOfDice ]; // array to store the dice to print as an
// int representing the eyes of the dice

// get values from Dice
for( int i = 0; i < numberOfDice; i++ )
{
// calls the member funciton of class Die called getDieValue(); which
// returns an int representing the result form the latest roll of the die
// and stores the value in array diceToPrint.

diceToPrint[ i ] = diceArray[ i ].getDieValue();

// the compiler gives following error for this line:
request for member `getDieValue' in `*((+(((unsigned int)i) * 4u)) + diceArray)', which is of non-class type `Die*'
}

/** Die pieces **/
// makes upp the illustrations
const string topDie = "-------";
// Bottom and top of the die looks the same.
// but different (specific) names makes it easier to read.
const string bottomDie = "-------";
const string sidesDie = "| |";
const string oneEye = "| * |";
const string twoEyes = "| * * |";
const string sideEyeLeft = "| * |";
const string sideEyeRight = "| * |";
/** end die pieces **/

const int numberOfFaces = 6; // contains the number of faces on the die
const int numberOfPieces = 3; // contains the number of pices for each die illustration

// diceArray with 6 rows (number of faces on a die) and 5 columns
// (number of pieces every face is built of)
const string diceArray[ numberOfFaces ][ numberOfPieces ] = {
{ sidesDie , oneEye , sidesDie }, // one eye
{ oneEye , sidesDie, oneEye }, // two eyes
{ sideEyeLeft, oneEye , sideEyeRight }, // three eyes
{ twoEyes , sidesDie, twoEyes }, // four eyes
{ twoEyes , oneEye , twoEyes }, // five eyes
{ twoEyes , twoEyes , twoEyes } // six eyes
}; // end diceArray

/** start printing dice illustrations **/

// print the top of the illustrations.
// All the pieces of the first row of the illustrations should always be the same
for ( int j = 0; j < numberOfDice; j++ )
{
printText( topDie ); // print the top piece of every die
printColumns( numberOfDice ); // print the pieces in five columns
}


// from the top left startprinting from diceArray
// loop through columns of diceArray
for( int k = 0; k < numberOfPieces; k++ )
{
// loop through the rows of diceArray
for( int l = 0; l < numberOfDice; l++ )
{
// print the die piece in the specified element
printText( diceArray [ diceToPrint[ l ] - 1 ][ k ]);
printColumns( numberOfDice ); // print dice in five columns
// there might be a problem here too, but I'm not sure ?!

} // end inner for
} // end outer for

// print the bottom of the illustrations.
// All the pieces of the last row of the illustrations should always be the same
for ( int m = 0; m < numberOfDice; m++ )
{
printText( bottomDie ); // print the bottom piece of every die
printColumns( numberOfDice ); // print the pices in five columns
}

/** End printing Die illustrations **/

} // end function printDice
// end of problematic function


I've taken away the definitions of most of the member functions in gameIO since I know they work (they are pretty much just using cout and cin to do their job). The printDice function worked before when I was just feeding it with an array of integers. Where each integer represented the number of eyes on the die. The problem started when I tried to rewrite the function to take an array of objects instead.

This gets long really quickly I hope someone is able and has the energy to help.

/Chris

BrickInTheWall
08-29-2009, 01:54 AM
Well I'm too lazy to go through your code, but I'd try this (I mainly code in C# so sorry if I'm causing memory leaks, but I think its fine):



#include <iostream>

using namespace std;

class MyClass
{
public:
int _x;

MyClass(int x)
{
_x = x;
}

MyClass()
{
_x = 20;
}
};

void AccessObjX(MyClass *pObj, int size)
{
MyClass *tempObjArray = new MyClass[size];
MyClass *deletePointer = tempObjArray;
tempObjArray = pObj;
delete deletePointer;
deletePointer = 0;

for (int i = 0; i < size; i++)
{
cout << tempObjArray[i]._x << endl;
}

tempObjArray[0]._x = 30;
}

int main(void)
{
MyClass myObj[2];
myObj[1]._x = 10;
AccessObjX(myObj, sizeof(myObj) / sizeof(MyClass));
cout << myObj[0]._x;

int endP;
cin >> endP;
return 0;
}


The only reason why I'm allocating memory in the function is because I want to create a temporary array of variable size. You don't really need deletePointer but I feel it puts emphasis on it.

edit: hah I did mess up. You're going to need delete[] instead of delete, sorry. If I keep it the way it is now, I'm only deleting part of what I allocated.

SirSkorpan
08-29-2009, 12:22 PM
I found the problem.

In the failing function I had done this



printDice( Die *diceArray, const int numberOfDice )
{
int dieValue[ numberOfDice ];

for( int i = 0; i < numberOfDice; i++ )
{
dieValue[ i ] = diceArray[ i ].getDieValue();
}

const string diceArray[6][3] = {.......}
}

So I had given the array I received in the function call the same name as another array I declared and initialized in the function. changed the name of the one received and now it works.

Great little walk-through on how you do it, thank you! It made me have to look through all of my code after reading your post cuz I felt we were doing pretty much the same thing.

But I understand why you didn't check all of my code It gets long quickly. Next time I think I need to make it a lot shorter.

Thank you!
/Chris

BrickInTheWall
08-29-2009, 04:15 PM
Yea yours works fine and is probably its better to use const to initialize the array, rather than allocate memory on the heap. Just note mine causes a memory leak right now.

SirSkorpan
08-29-2009, 05:49 PM
As said, I'm new so, I'm eager to learn. I'm trying to figure out this memory leak you were talking about. (We just had pointers in class so I thought of it as good practice). Have I gotten this correctly? (see comments in code below)



void AccessObjX(MyClass *pObj, int size)
{
MyClass *tempObjArray = new MyClass[size]; // here you allocate memory for an array
// of MyClass-objects (of variable
// length/size)

MyClass *deletePointer = tempObjArray; // creates another array which now points to
// the same memory as tempObjArray

tempObjArray = pObj; // tempObjArray now points to same memory as pObj so
// tempObjArray and deletePointer nolonger points to
// same memory, right?

delete [] deletePointer; // deletePointer nolonger points to a specific place in
// memory but can point to pretty much anything in memory?
// I took the liberty to ad the []-operator :)

deletePointer = 0; // so you set deletePointer be a NULL pointer

// prints the values of _x for each MyClass-object in the tempObjArray
for (int i = 0; i < size; i++)
{
cout << tempObjArray[i]._x << endl;
}

tempObjArray[0]._x = 30; // assign 30 to _x in first MyClass-object of tempObjArray

// should you here delete tempObjArray as well? To prevent memory leak, as such:
delete [] tempObjArray; // tempObjArray nolonger points to any specific memory
tempObjArray = 0; // tempObjArray is now NULL pointer
}


int main(void)
{
MyClass myObj[2]; //creates an array with two objects
myObj[1]._x = 10; // sets _x of second object in array

AccessObjX(myObj, sizeof(myObj) / sizeof(MyClass)); // sizeof(myObj) gives number of bytes
// in array and sizeof(MyClass) gives
// number of bytes in a MyClass object
// division gives number of objects
// in array

cout << myObj[0]._x; // acess and print _x of first element in array myObj
// (which were set to 30 before)

int endP;
cin >> endP;
return 0;
}

Is it causing a memory leak because you don't delete the whole of the deletePointer array? Or do you also need to delete tempObjArray as well (as I tried in the code above). Or is there something else that I don't see?

Thanks again!
/Chris

BrickInTheWall
08-30-2009, 01:59 AM
Using delete on tempObjArray should cause an exception to be thrown as it is not pointing to anything on the heap (so nothing that was allocated dynamically).
Thats like doing the following:
int myInt[3];
// Initialize array.
delete myInt;

Also my mistake was using delete rather than delete[] on the deletePointer. If you use delete on a dynamically allocated array then they will be deleted but it can cause some weird behavior. You can't just delete part of an array, that doesn't work. But you might be deleting something else too.
From what I have learned, using new[] (like in 'int *myInt = new int[2]'), C++ caches the amount of elements in the array somewhere, and when using delete[], it retrieves this amount, making sure you delete the correct amount of elements. I would double check this though as that explanation might be a bit vague. I hardly program in C++ anymore so I'm a bit rusty.

SirSkorpan
08-30-2009, 10:37 PM
From what I have learned, using new[] (like in 'int *myInt = new int[2]'), C++ caches the amount of elements in the array somewhere, and when using delete[], it retrieves this amount, making sure you delete the correct amount of elements. I would double check this though as that explanation might be a bit vague. I hardly program in C++ anymore so I'm a bit rusty.

Ah I get it, yes that goes pretty much in line with what our book says too. So yes then it was only the [] missing in the code. Thank you!

BrickInTheWall
08-31-2009, 02:11 AM
Ah I get it, yes that goes pretty much in line with what our book says too. So yes then it was only the [] missing in the code. Thank you!
I'm curious, what book are you reading? By saying "our book" are you learning to program at college or uni? Just wanna know what literature you're working with. I can never have enough books as references :).

SirSkorpan
08-31-2009, 11:53 AM
I'm studying at the Umea University in Sweden. The book we use is: "C++ how to program 6th ed" by Deitel. I think it's a really good book at least for me who hasn't programmed at all before taking this course (some java script but that barely counts).



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum