Sign in to follow this  
KyleM

Help on passing pointers

Recommended Posts

KyleM    151
I decided to make a little text - based horse racing simulator. I have run into some trouble. The horses and thier property's come from a struct called horse, each horse is declared and their property's are changed in the same .cpp file. Another file needs to acsess these structs. I tried making a pointer to each struct. but i dont really have a way in my head on how to pass them menu.cpp - This is the file that needs the struct.
#include "stdafx.h"
#include <iostream>
#include "windows.h"
#include "horses.h"

using namespace std;

//Call and draw the menu
void displayMenu()
{
	cout<<"\nYou walk up to the betting stands, the horse's statistics are\ndisplayed on a screen"<<endl;
	
}






//Text Functions
void clear_screen()
{
	system("cls");
}

void stall_program(int milleseconds_to_stall)
{
	Sleep(milleseconds_to_stall);
}

void call_horse_stats()
{
	cout<<"\nCharlie - Wins: ";
}


horses.cpp
#include "stdafx.h"
#include <string>
#include <iostream>

using namespace std;

     
  struct horse
	{
		string name;
		int wins;
		int losses;
		double percentChanceOfWining;

	};




//the function used to calculate the horses chances
	double calculate_horses_chances(int wins,int losses)
{

	double horsesChance = (wins / losses) * 100;

	return horsesChance;
}



//initiliaze the horses stats
void init_horses()
{
	
//initliaze the horses
horse charlie;
horse cooldude;
horse shiningFury;
horse burningSoap;
horse smellyPages;

//Set the horses names
charlie.name = "Charlie";
cooldude.name = "Cool Dude";
shiningFury.name = "Shining Fury";
burningSoap.name = "Burning Soap";
smellyPages.name = "Smelly Pages";

//set each horse's wins/losses to a number beetween  1 and 5
//to make it seem like the horse's have raced before and dont have 0 percent odds 

charlie.wins = rand() % 5 + 1;
charlie.losses = rand() % 5 + 1;

cooldude.wins = rand() % 5 + 1;
cooldude.losses = rand() % 5 + 1;

shiningFury.wins = rand() % 5 + 1;
shiningFury.losses = rand() % 5 + 1;

burningSoap.wins = rand() % 5 + 1;
burningSoap.losses = rand() % 5 + 1;

smellyPages.wins = rand() % 5 + 1;
smellyPages.losses = rand() % 5 + 1;


//set up their percent chance of winning
charlie.percentChanceOfWining = calculate_horses_chances(charlie.wins, charlie.losses);
cooldude.percentChanceOfWining = calculate_horses_chances(cooldude.wins, cooldude.losses);
shiningFury.percentChanceOfWining = calculate_horses_chances(shiningFury.wins, shiningFury.losses);
burningSoap.percentChanceOfWining = calculate_horses_chances(burningSoap.wins, burningSoap.losses);
smellyPages.percentChanceOfWining = calculate_horses_chances(smellyPages.wins, smellyPages.losses);


//Set up pointers to the horses
horse * pntrCharlie = &charlie;
horse * pntrCoolDude = &cooldude;
horse * pntrShiningFury = &shiningFury;
horse * pntrSmellyPages = &smellyPages;
}


Any help would be greatly appreciated. :)

Share this post


Link to post
Share on other sites
CornyKorn21    624
One suggestion would be to declare the horses outside of your initialization function. This way you can access them in other places.


//.h
horse charlie;
horse cooldude;
horse shiningFury;
horse burningSoap;
horse smellyPages;

//.cpp
init_horses()
{
...
}


Share this post


Link to post
Share on other sites
Deliverance    387
Quote:
Original post by KyleM
I decided to make a little text - based horse racing simulator. I have run into some trouble. The horses and thier property's come from a struct called horse, each horse is declared and their property's are changed in the same .cpp file. Another file needs to acsess these structs. I tried making a pointer to each struct. but i dont really have a way in my head on how to pass them

menu.cpp - This is the file that needs the struct.
*** Source Snippet Removed ***





horses.cpp
*** Source Snippet Removed ***


Any help would be greatly appreciated. :)


This would be a messy solution but you could try doing this:


#include "stdafx.h"
#include <iostream>
#include "windows.h"
#include "horses.h"

extern horse * pntrCharlie;
extern horse * pntrCoolDude;
extern horse * pntrShiningFury;
extern horse * pntrSmellyPages;


using namespace std;

//Call and draw the menu
void displayMenu()
{
cout<<"\nYou walk up to the betting stands, the horse's statistics are\ndisplayed on a screen"<<endl;

}


//Text Functions
void clear_screen()
{
system("cls");
}

void stall_program(int milleseconds_to_stall)
{
Sleep(milleseconds_to_stall);
}

void call_horse_stats()
{
cout<<"\nCharlie - Wins: ";
}





#include "stdafx.h"
#include <string>
#include <iostream>

using namespace std;


struct horse
{
string name;
int wins;
int losses;
double percentChanceOfWining;

};


//Set up pointers to the horses
horse * pntrCharlie = NULL;
horse * pntrCoolDude = NULL;
horse * pntrShiningFury = NULL;
horse * pntrSmellyPages = NULL;


//the function used to calculate the horses chances
double calculate_horses_chances(int wins,int losses)
{

double horsesChance = (wins / losses) * 100;

return horsesChance;
}



//initiliaze the horses stats
void init_horses()
{

//initliaze the horses
horse charlie;
horse cooldude;
horse shiningFury;
horse burningSoap;
horse smellyPages;

//Set the horses names
charlie.name = "Charlie";
cooldude.name = "Cool Dude";
shiningFury.name = "Shining Fury";
burningSoap.name = "Burning Soap";
smellyPages.name = "Smelly Pages";

//set each horse's wins/losses to a number beetween 1 and 5
//to make it seem like the horse's have raced before and dont have 0 percent odds

charlie.wins = rand() % 5 + 1;
charlie.losses = rand() % 5 + 1;

cooldude.wins = rand() % 5 + 1;
cooldude.losses = rand() % 5 + 1;

shiningFury.wins = rand() % 5 + 1;
shiningFury.losses = rand() % 5 + 1;

burningSoap.wins = rand() % 5 + 1;
burningSoap.losses = rand() % 5 + 1;

smellyPages.wins = rand() % 5 + 1;
smellyPages.losses = rand() % 5 + 1;


//set up their percent chance of winning
charlie.percentChanceOfWining = calculate_horses_chances(charlie.wins, charlie.losses);
cooldude.percentChanceOfWining = calculate_horses_chances(cooldude.wins, cooldude.losses);
shiningFury.percentChanceOfWining = calculate_horses_chances(shiningFury.wins, shiningFury.losses);
burningSoap.percentChanceOfWining = calculate_horses_chances(burningSoap.wins, burningSoap.losses);
smellyPages.percentChanceOfWining = calculate_horses_chances(smellyPages.wins, smellyPages.losses);


//Set up pointers to the horses
pntrCharlie = &charlie;
pntrCoolDude = &cooldude;
pntrShiningFury = &shiningFury;
pntrSmellyPages = &smellyPages;
}

Share this post


Link to post
Share on other sites
rip-off    10979
Pass the horses to the displayMenu function. You will need a container of some sort. An array is a primitive container.

You will need to move types and functions that are required in multiple files into a header file.

For example, horse.hpp

#ifndef HORSE_HPP
#define HORSE_HPP

#include <string>

struct Horse
{
string name;
int wins;
int losses;
double percentChanceOfWining;
};

const int MaxHorses = 5;

struct Race
{
Horse horses[MaxHorses];
};

void printHorseInfo(Horse horse);

#endif



And menu.cpp

#include "stdafx.h"
#include <iostream>
#include "windows.h"
#include "horses.h"

using namespace std;

//Call and draw the menu
void displayMenu(Race race)
{
cout << "\nYou walk up to the betting stands, the horse's statistics are\ndisplayed on a screen" << endl;

for(int i = 0 ; i < MaxHorses ; ++i)
{
printHorseStatistics(race.horses[i]);
}
}



Then your "init_horses" could return a Race, which in turn returns the horses

// initiliaze the horses stats
Race init_horses()
{
// initliaze the horses
horse charlie;
horse cooldude;
horse shiningFury;
horse burningSoap;
horse smellyPages;

//Set the horses names
charlie.name = "Charlie";
cooldude.name = "Cool Dude";
shiningFury.name = "Shining Fury";
burningSoap.name = "Burning Soap";
smellyPages.name = "Smelly Pages";

//set each horse's wins/losses to a number beetween 1 and 5
//to make it seem like the horse's have raced before and dont have 0 percent odds

charlie.wins = rand() % 5 + 1;
charlie.losses = rand() % 5 + 1;

cooldude.wins = rand() % 5 + 1;
cooldude.losses = rand() % 5 + 1;

shiningFury.wins = rand() % 5 + 1;
shiningFury.losses = rand() % 5 + 1;

burningSoap.wins = rand() % 5 + 1;
burningSoap.losses = rand() % 5 + 1;

smellyPages.wins = rand() % 5 + 1;
smellyPages.losses = rand() % 5 + 1;


//set up their percent chance of winning
charlie.percentChanceOfWining = calculate_horses_chances(charlie.wins, charlie.losses);
cooldude.percentChanceOfWining = calculate_horses_chances(cooldude.wins, cooldude.losses);
shiningFury.percentChanceOfWining = calculate_horses_chances(shiningFury.wins, shiningFury.losses);
burningSoap.percentChanceOfWining = calculate_horses_chances(burningSoap.wins, burningSoap.losses);
smellyPages.percentChanceOfWining = calculate_horses_chances(smellyPages.wins, smellyPages.losses);

Race race = { charlie, cooldude, shiningFury, burningSoap, smellyPages };
return race;
}


Any function that needs access to the horses can be passed the race instance, or just a single horse if that is all that is required. This is a simple example, leaving aside dynamic containers and pass by reference.

One final thing, the following calculation probably won't work for you:

(wins / losses) * 100;

C++ will use integer division unless one of the types is a float or double. This means that the result is the same as division with the remainder discarded. You can change the types of the variables involved, use a cast or simply rearrange the code such that the constant 100.0 is used as the center of the operation:

(wins * 100.0 / losses);

Now the integers are "upgraded" or "promoted" to doubles and you won't have the same problem of the remainder being discarded.

You probably should include a special check in the case losses is 0.

Share this post


Link to post
Share on other sites
KyleM    151
Thanks for the help people. Is passing by pointer not a mroe efficent way to do this, im trying to learn and i was just wondering if it's what i should use here. As for the program im going to try rip-off's way. Thanks guys :)

Share this post


Link to post
Share on other sites
nGamer    184
I am uncertain if you are declaring memory on the heap or not. If you are, take caution when passing pointers around in the code that carry addresses to the heap. Generally, the function that created that pointer should be the same function that deletes the pointer.

Share this post


Link to post
Share on other sites
rip-off    10979
Your computer can easily handle copying the couple of bytes that make up a Horse or a Race.

However, as I alluded to in my post, passing by reference is idiomatic in C++. Passing by const reference is safe, it incurs no unnecessary copies and also protects the data by marking it as "const", which prevents it being accidentally modified in the function.

For example, a small change like this to printHorseInfo():

void printHorseInfo(const Horse &horse);

This change needs to be made to both the declaration and definition. Note that the function body does not need to change.

Likewise, displayMenu could be:

void displayMenu(const Race &race)

References are usually a better choice than raw pointers in modern C++. Pointers are generally only used in a handful of situations, and most of these can be wrapped safely. One example is where a "null" value makes sense. It wouldn't make sense to print a null horse, so printHorseInfo() shouldn't take a pointer. But sometimes optional types make sense. For example, a homing rocket launcher might have a target. But if there is nothing to target at the moment then the rocket's target might be set to "null" to indicate this. However, we could use boost::optional to indicate this.

Dynamic allocation and polymorphism are two more cases where pointers might be used. But in modern C++ we would use smart pointers or containers, such as std::shared_ptr<> or std::vector<> to handle such cases.

Share this post


Link to post
Share on other sites
nGamer    184
In addition to the use of vectors, they manage object memory for you, however, you must remember to clear the vector before it goes out of scope.

Share this post


Link to post
Share on other sites
nGamer    184
Quote:
Original post by rip-off
std::vector does not require you to clear it, it is a RAII type.


Is this true even if the vector holds pointers? Does the vector automatically call the destructors?

Share this post


Link to post
Share on other sites
rip-off    10979
The vector cleans up any memory *it* allocates, not memory you have allocated. For instance, if you build a vector of pointers to stack objects, or a vector containing duplicate pointers, then having the vector delete the pointed-at objects would be undefined behaviour.

For a vector of pointers, the memory allocated for the pointers is cleared, not the pointees. The destructors of any type you place in the vector will be called. Its really quite intuitive to use.

You can use boost::ptr_vector<> to get the behaviour you are inquiring about.

Share this post


Link to post
Share on other sites
KyleM    151
I am feeling quite stupid at the moment, but the main.cpp file does not know about the race instance, it knows about the Race struct, but not the instance, which confuses me as menu.cpp knows about it and that includes the same things as main.cpp.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by KyleM
I am feeling quite stupid at the moment, but the main.cpp file does not know about the race instance, it knows about the Race struct, but not the instance, which confuses me as menu.cpp knows about it and that includes the same things as main.cpp.


#include of a header is a literal copy-and-paste. Because the header defines the structure, #including the header lets the current source code know about the structure.

The entire concept of an instance doesn't even make sense until the program is running. Variables are not instances; values are. You pass values to a function when you call it. The parameters simply say what kinds of values to expect (which, in turn, lets the compiler check that the calls make sense).

"The instance" is not a phrase you should be using. The entire point of a struct is that it defines a data type. You can make as many instances of it as you like, just as you can have as many ints as you like. So there is some specific instance that you are interested in.

Well, you have to understand that values and variables are different things. A variable is a name that we give to a value within a certain context (scope). A value is a chunk of memory that is interpreted in a certain way according to its type.

When you pass a value to a function, you are saying "the name <name of parameter> will apply to <the result of this expression> for this time that the function is called". For example:


// We have a function like:
void foo(int x) {
// we don't care what it actually does
}

// And then somewhere we call it like:
foo(42*23);


Notice for our example that there isn't any variable being passed. We write an expression, '42*23', which is evaluated to produce the value, 966. Then we call the function named 'foo', passing 966 as the value for the parameter 'x'. The compiler accepts this because it knows that multiplying 42*23 will produce an int, and 'x' is an int. (It doesn't necessarily do this multiplication ahead of time, although it is allowed to when it has all the information ahead of time.) Then, within the body of 'foo', the variable (parameter, really; but it's treated the same way) 'x' is of type 'int' and holds the value 966 (unless it gets changed later, of course).

You can do the same sort of thing if the type is Race rather than int. (Although obviously you can't multiply two Races together.) The function has a parameter of a certain type, and you pass a value which that parameter will refer to. The concept of "knowing about instances" doesn't really make sense here. The function operates blindly: it has its own name for whatever is passed in, and the calling code passes in whatever data is valid, whether it has the same name (or any name!) or not.

Share this post


Link to post
Share on other sites
iMalc    2466
Here's one example of how to reduce that nasty repetition you've got going there and do this in a more object-oriented way:
struct Horse
{
string name;
int wins;
int losses;
double percentChanceOfWining;

// Give the Horse initial values using a "constructor initialisation list"
Horse(const char *name) : name(name),
wins(rand() % 5 + 1), losses(rand() % 5 + 1),
percentChanceOfWining(calculate_horses_chances(wins, losses))
{
}
};

// Give each horse it's name and other initial values as it's created
horse charlie("Charlie");
horse cooldude("Cool Dude");
horse shiningFury("Shining Fury");
horse burningSoap("Burning Soap");
horse smellyPages("Smelly Pages");
Your init_horses function is now gone!

Share this post


Link to post
Share on other sites
KyleM    151
Hey man, thanks for the help but i made this program to test out what i have learnt so far,and constructors isint something i have covered yet :(

Share this post


Link to post
Share on other sites
nGamer    184
Quote:
Original post by KyleM
Hey man, thanks for the help but i made this program to test out what i have learnt so far,and constructors isint something i have covered yet :(


Don't worry, constructors aren't difficult to understand. In a C++ class, in simplest terms, the constructor is responsible for creating an instance of the class. It accomplishes this by reserving any memory needed by the class variables and initializing them.

The advantages of classes over structs is the ability to have class functions (methods).

Share this post


Link to post
Share on other sites
rip-off    10979
Quote:

The advantages of classes over structs is the ability to have class functions (methods).

Incorrect. In C++, structs can have functions, constructors, virtual functions, private members.

The only differences between "struct" and "class" are:

  • structure members are public by default, whereas class defaults to private

  • structures use public inheritance by default, classes default to private


You may notice that the differences are soley in the access level defaults, and thus can be easily changed.

Share this post


Link to post
Share on other sites
nGamer    184
Quote:
Original post by nGamer
Quote:
Original post by KyleM
Hey man, thanks for the help but i made this program to test out what i have learnt so far,and constructors isint something i have covered yet :(


The advantages of classes over structs is the ability to have class functions (methods).


The advantages of classes over 'C' structs.

Share this post


Link to post
Share on other sites
DevFred    840
Quote:
Original post by nGamer
the constructor is responsible for creating an instance of the class. It accomplishes this by reserving any memory needed by the class variables and initializing them.

Constructors do not reserve memory. Initialization is their only purpose.

Share this post


Link to post
Share on other sites

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