I'm pretty new to C++, but this has got me stumped. I'm working on the base code for an RPG, but this one character in the class has got me stumped. I've isolated the pieces at issue here (there's a good 1000 lines cut out), and the problem remains.
Here's the class and header for the program:
#include <iostream>
#include <cstdlib>
using namespace std;
unsigned long errorcount;
// I know this is bad coding, but it's not going to be in the end product...
class character {
public:
void setgender(char newgender);
char getgender() const;
private:
char gender;
};
void character::setgender(char newgender) {
switch (newgender) {
case 'M': gender = 'M'; break;
case 'F': gender = 'F'; break;
default: gender = '0'; errorcount++; break;
}
std::cout << "\nDuring setgender function: " << gender;
return;
}
char character::getgender() const {
std::cout << "\nDuring getgender function: " << gender;
return gender;
}
This next part that has me scratching my head. I started the following code:
void PlayerCharacterCreation(character Player) {
string newgender;
while(true) {
std::cout << "\nAre you male or female?" << "\n1. Male" << "\n2. Female" << "\n::";
std::cin >> newgender;
if (newgender == "1") { Player.setgender('M'); break; }
if (newgender == "2") { Player.setgender('F'); break; }
std::cout << "\nInvalid response. Try again.";
}
std::cout << "\nAfter setgender function: " << Player.getgender();
}
void PlayerCreationTest() {
character Test;
PlayerCharacterCreation(Test);
char playergender = Test.getgender();
if (playergender != 'M' && playergender != 'F') { errorcount++; }
std::cout << "\nAfter getgender function: " << playergender;
std::cout << "\n\nOUTPUT BEGINS NOW\nGender: " << playergender << "\n";
std::cout << "OUTPUT ENDS. Total Errors: " << errorcount << ".";
return;
}
int main() {
PlayerCreationTest();
return 0;
}
Now as far as I can tell, there's nothing wrong with any of this - the (GCC) compiler doesn't complain, and it works just fine up to a point. But if I run it, I get the following output:
Are you male or female?
1. Male
2. Female
1
During setgender function: M
During getgender function: M
After setgender function: M
During getgender function: #
After getgender function: #
OUTPUT BEGINS NOW
Gender: #
OUTPUT ENDS. Total Errors: 1.
Worse than that, if I choose option "2" the output is the same only when it makes no sense:
Are you male or female?
1. Male
2. Female
2
During setgender function: F
During getgender function: F
After setgender function: F
During getgender function: #
After getgender function: #
OUTPUT BEGINS NOW
Gender: #
OUTPUT ENDS. Total Errors: 1.
In other words, the expected output goes badly wrong somewhere between the last line of PlayerCharacterCreation(), and the very next line of the PlayerCreationTest().
As far as I can tell, though, the "character" class should stay the same between functions, not change all willy-nilly like this.
I hope that's enough for someone to figure out what I'm doing wrong, but I was toying with it a little and managed to change the output character even more.
By adding an "srand(0)" line at the beginning of the main function, I can change the '#' to a 'y' for both options 1 and 2.
By adding a "GenderTest()" line at the beginning of the main function, I can change the '#' to a 'F', for both options. If I add both lines, only the one immediately above the "PlayerCreationTest()" line seems to matter. Which is odd, because the full code always returns an 'l' (lowercase L) instead of '#', and the main function is exactly the same as written above.
As far as I can tell, though, the "character" class should stay the same between functions, not change all willy-nilly like this.
Well, you're wrong. They do stay the same, because they are seperate variables. PlayerCharacterCreation creates a local character (a copy of Test), and at the end of the function, the object is destroyed.
The original character that you passed to PlayerCharacterCreation never changed, and you get some weird output because the gender was never set for that character.
The Player in PlayerCharacterCreation is a totally new character, it is not Test :)
If you want to modify the character passed to PlayerCharacterCreation, you have to pass it by reference (there are some other ways too, like passing a pointer, returning Player, but that's the best one):
void PlayerCharacterCreation(character& Player);
^^^
reference
void PlayerCharacterCreation(character Player)
Inside this function, Player is a local instance of character into which the calling parameter is copied. Consider the following:
#include <iostream>
void f1(int x) {
x++;
}
void f2(int i) {
i++;
}
int main() {
int i = 0;
f(i);
std::cout << i << '\n';
}
We know that the output from this will be '0', because f1::x and f2::i are their own independent variables copied from our source parameter.
If you want to pass a specific instance of a variable rather than a copy of it, you need to provide a pointer or a reference.
void by_pointer(Character* player) {
if (player == nullptr) {
error_handling();
}
player->do_thing();
}
by_pointer(&player);
void by_reference(Character& player) {
player.do_thing();
}
by_reference(player);
Example:
#include <iostream>
int f1(int& param) {
param++;
}
int main() {
int i = 0;
f1(i);
std::cout << i << '\n'; // outputs 1
}
Related
I have a function which takes an int value from another function. When I type a wrong int value it works as intended (calls the same function recursively & lets me enter a new number) but when I type anything other than an int (a, %, etc) it calls the function recursively but gets stuck in an infinite loop. Any help/insight would be great as I am in the learning stages of C++ Programming.
Here is my Full code snippet (49 Lines)
To summarize what I am asking is how would I properly go about displaying an error and returning back to the Main Menu without triggering the infinite loop when a non-int value is given.
int MainMenu();
void MainMenuSelection(int x);
int main()
{
MainMenuSelection(MainMenu());
return 0;
}
int MainMenu() {
int selection;
std::cout << "C++ Tutorials Main Menu\n";
std::cout << "----------------------------------------------\n";
std::cout << "1 - Chapter #1\n";
std::cout << "2 - Chapter #2\n";
std::cout << "3 - Chapter #3\n";
std::cout << "----------------------------------------------\n";
std::cout << "Please enter a cooresponding value: ";
std::cin >> selection;
if (std::cin.fail()) {
std::cout << "Input must be an integer";
}
else {
return selection;
}
}
void MainMenuSelection(int x) {
if (x == 1) {
std::cout << "\nChapter #1 is unavailable.\n";
std::cout << std::string(22, '\n');
MainMenuSelection(MainMenu());
}
else if (x == 2) {
std::cout << std::string(2, '\n');
ChTwoMenuSelection(ChTwoMenu());
}
else if (x == 3) {
std::cout << std::string(2, '\n');
ChThreeMenuSelection(ChThreeMenu());
}
else {
std::cout << "\nThere was an incorrect value submitted.";
std::cout << std::string(22, '\n');
MainMenuSelection(MainMenu());
}
}
The function MainMenuSelection( int x ) requires an int. The function call in the main function thinks it gets this by calling a function which should return an int namely int MainMenu(). But this function does not do what you should expect from a function which has been declared in this way. You should make sure that a function should ALWAYS return the value (except for a void of course).
There are static code analyzers like Cppcheck which can help you to analyse your code and find possible problems like the one you stated above.
Another tip would be to think about what happens when you execute the code. Especially when your code is still quite small you can manually go through the statements to see what path it takes, so you can find out where the program fails.
I'm a beginner in C++ and yesterday i did my first step with the OO (Object Oriented).
I made a programm that has a character class (Personnage), i made three variables for the character, vie, mana and degat.
I made also a function in the class which is attack and it should remove health from john, but when i show the health of john with another function i see 100, can someone help me please ?
#include <iostream>
#include <string>
using namespace std;
class Personnage
{
public:
void montrer()
{
cout << vie << endl;
}
void attaquer(Personnage john)
{
vie = vie - degat;
if (vie < 0)
{
vie = 0;
}
}
private:
int degat = 50;
int vie = 100;
int mana = 100;
};
int main
{
int action(0), degat;
Personnage jack, john;
cout << "What action do you want to do ?" << endl;
cout << "1-Attack your ennemy." << endl;
cout << "2-Take some life" << endl;
cout << "3-Take some mana." << endl;
cin >> action;
switch(action)
case '1':
jack.attaquer(john);
john.montrer();
return 0;
}
First, you must do "case 1" instead of " case '1' " because your variable is integer. However, this wont solve your problem, and you will still see john's state unaffected by the call of the method "attaquer". Why? because method attaquer is invoked on the personnage Jack, not John. If you want the method to change the health of the attacked Paersonnage, not the attacking one, you should make it like this:
void attaquer(Personnage& victime) // notice the &, pass by reference
{
victime.vie -= degat;
if (victime.vie < 0)
{
victime.vie = 0;
}
}
void attaquer(Personnage john)
{
vie = vie - degat;
if (vie < 0)
{
vie = 0;
}
}
vie and degat both refer to the fields of the object the method was called from. You call attaquer from jack, so jack's data changes. You then call john.montrer(), which will show john's untarnished data.
I assume you intended that attaquer affect the Personnage passed to it. To alter the passed parameter:
void attaquer(Personnage john)
{
john.vie = john.vie - degat;
if (john.vie < 0)
{
john.vie = 0;
}
}
You have to specify that you want to use a different object's data. This, however, is not a complete solution because void attaquer(Personnage john) takes a Personnage by value. This means it copies the object you give it, and that new copy disappears at the end of the function. Make it a reference like:
void attaquer(Personnage& john)
This will affect the original object you sent to the function.
Of course, this answer points out that your switch statement is comparing an integer to a character 1 and '1' are two different values.
I've been pulling my hair out trying to figure out this program. The class has to hold 3 player's info and output their info. My output function is not outputting from my set/get functions. Also, if I output the array indexes the program crashes (that's the array indexes are commented out in the Output function).
edit: I'll just show one profile to keep the code smaller
Any help is appreciated.
#include <cstdlib>
#include <iostream>
using namespace std;
class PlayerProfile
{
public:
void output();
void setName1(string newName1); //player's name
void setPass1(string newPass1); //player's password
void setExp1(int newExp1); //player's experience
void setInv1(string newInv1[]); //player's inventory
void setPos1(int newX1, int newY1); //player's position
string getName1();
string getPass1();
int getExp1();
string getInv1();
int getPos1();
private:
string name1;
string pass1;
int exp1;
string inv1[];
int x1;
int y1;
};
int main(int argc, char *argv[])
{
PlayerProfile player;
cout << "This program generates three player objects and displays them." << endl;
cout << endl;
player.output();
system("PAUSE");
return EXIT_SUCCESS;
}
void PlayerProfile::setName1(string newName1)
{
newName1 = "Nematocyst";
name1 = newName1;
}
void PlayerProfile::setPass1(string newPass1)
{
newPass1 = "obfuscator";
pass1 = newPass1;
}
void PlayerProfile::setExp1(int newExp1)
{
newExp1 = 1098;
exp1 = newExp1;
}
void PlayerProfile::setInv1(string newInv1[])
{
newInv1[0] = "sword";
newInv1[1] = "shield";
newInv1[2] = "food";
newInv1[3] = "potion";
inv1[0] = newInv1[0];
inv1[1] = newInv1[1];
inv1[2] = newInv1[2];
inv1[3] = newInv1[3];
}
void PlayerProfile::setPos1(int newX1, int newY1)
{
newX1 = 55689;
x1 = newX1;
newY1 = 76453;
y1 = newY1;
}
string PlayerProfile::getName1()
{
return name1;
}
string PlayerProfile::getPass1()
{
return pass1;
}
int PlayerProfile::getExp1()
{
return exp1;
}
string PlayerProfile::getInv1()
{
return inv1[0], inv1[1], inv1[2], inv1[3];
}
int PlayerProfile::getPos1()
{
return x1, y1;
}
void PlayerProfile::output()
{
cout << "Player Info - " << endl;
cout << "Name: " << name1 << endl;
cout << "Password: " << pass1 << endl;
cout << "Experience: " << exp1 << endl;
cout << "Position: " << x1 << ", " << y1 << endl;
cout << "Inventory: " << endl;
/*cout << inv1[0] << endl;
cout << inv1[1] << endl;
cout << inv1[2] << endl;
cout << inv1[3] << endl; */
}
This is the output that I am getting:
This program generates three player objects and displays them.
Player Info -
Name:
Password:
Experience: -2
Position: 3353072, 1970319841
Inventory:
Press any key to continue . . .
I'm sorry if I sound like an idiot, this is the first time I have programmed with classes and I am very confused.
First:
You do not have a constructor declared or defined in your class so when you compile, the compiler provides you with a default constructor.
The line
PlayerProfile player;
calls the default constructor provided by the compiler. This default constructor only allocates memory for your class member variables, but does not set their values. This is why name1, pass1, exp1, x1, y1 are not outputting what you expect.
Second:
C++ will not call get or set functions for you, and I think you are misunderstanding how c++ functions work.
this
void PlayerProfile::setName1(string newName1)
{
name1 = newName1;
}
is a function definition. You do not need to assign newName1 inside the function. It's value is passed to the function when a line like
setName1("Nematocyst");
is executed.
If you write a constructor, you can use it to call your set functions, and pass them the values you want to set member variables to.
If you do not want to write a constructor, you can call class functions/methods from main with:
player.setName1("Nematocyst");
Third:
Your program crashes because you are not using arrays properly. Here is a tutorial on how to declare an array and access it's contents.
Generally, I think you are trying to run before you know how to walk. Try not to get frustrated. Learn how arrays work, how functions work, and then how classes work. I hope this is not your homework assignment!
This program works and does what is required. My question is in regards to the ReverseName function, and how it works exactly. I was able to reverse engineer it from some examples in my book, but I cant quite figure out how it works. I get Name is sent to it. i just dont understand how it is printed in reverse.
#include <iostream>
using namespace std;
void ReverseName(char *s );
int main(void){
char Name[] ="John Doe";
cout << "Name is: " << Name << "\n" << "Name Backwards is: " ;
ReverseName(Name);
cout << "\nName is: "<< Name << '\n';
return 0;
}
void ReverseName(char * s){
if(*s){
ReverseName(s+1);
cout << *s;
}
return;
}
void ReverseName(char * s){
if(*s){
ReverseName(s+1); // come into the end of the string
cout << *s;
}
return;
}
it just like this:
'J'
call --> 'o'
call ---> 'h'
call ---> ...
call ---> 'e' (Recursion to the end)
and when the stack come to the end of recursion, it will execute back in order. then it just like.
cout << 'e'
cout << ...
cout << 'h'
cout << 'o'
cout << 'J'
(come back from the call stack)
It's a recursive function.
It gets a pointer to a char array and calls itself until the the end of char array is reached, then it "unwinds" the recursion, printing all the chars from the back.
ReverseName() is a recursive function.
http://www.learncpp.com/cpp-tutorial/710-recursion/
I have the following functor:
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
It is supposed to be a strict weak ordering, and it's this long (could be one line only) for debug purposes.
I'm using this functor as a comparator functor for a stl::set. Problem being, it only inserts the first element. By adding console output to the comparator function, I learned that it's actually comparing the file name to itself every time.
Other relevant lines are:
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
and
// (FileSet files_;) <- SimulatedDisk private class member
void SimulatedDisk::addFile(SimulatedDiskFile * file) {
files_.insert(file);
positions_calculated_ = false;
}
EDIT: the code that calls .addFile() is:
current_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
current_request++;
}
Where all_requests is a list, and class Request is such that:
class Request {
private:
string file_name_;
int response_code_;
int response_size_;
public:
void setFileName(string file_name);
string getFileName();
void setResponseCode(int response_code);
int getResponseCode();
void setResponseSize(int response_size);
int getResponseSize();
};
I wish I could offer my hypotesis as to what's going on, but I actually have no idea. Thanks in advance for any pointers.
There's nothing wrong with the code you've posted, functionally speaking. Here's a complete test program - I've only filled in the blanks, not changing your code at all.
#include <iostream>
#include <string>
#include <set>
using namespace std;
class SimulatedDiskFile
{
public:
string getFileName() { return name; }
SimulatedDiskFile(const string &n)
: name(n) { }
string name;
};
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
int main()
{
FileSet files;
files.insert(new SimulatedDiskFile("a"));
files.insert(new SimulatedDiskFile("z"));
files.insert(new SimulatedDiskFile("m"));
FileSet::iterator f;
for (f = files.begin(); f != files.end(); f++)
cout << (*f)->name << std::endl;
return 0;
}
I get this output:
z and a: false
a and z: true
z and a: false
m and a: false
m and z: true
z and m: false
a and m: true
m and a: false
a
m
z
Note that the set ends up with all three things stored in it, and your comparison logging shows sensible behaviour.
Edit:
Your bug is in these line:
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
You're taking the address of a local object. Each time around the loop that object is destroyed and the next object is allocated into exactly the same space. So only the final object still exists at the end of the loop and you've added multiple pointers to that same object. Outside the loop, all bets are off because now none of the objects exist.
Either allocate each SimulatedDiskFile with new (like in my test, but then you'll have to figure out when to delete them), or else don't use pointers at all (far easier if it fits the constraints of your problem).
And here is the problem:
SimulatedDiskFile temp_file(current_request->getFileName(),
current_request->getResponseSize());
disk.addFile(&temp_file);
You are adding a pointer to a variable which is immediately destroyed. You need to dynamically create your SDF objects.
urrent_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(...blah..blah..); ====> pointer to local variable is inserted
disk.addFile(&temp_file);
current_request++;
}
temp_file would go out of scope the moment next iteration in while loop. You need to change the insert code. Create SimulatedDiskFile objects on heap and push otherwise if the objects are smaller then store by value in set.
Agree with #Earwicker. All looks good. Have you had a look inside all_requests? Maybe all the filenames are the same in there and everything else is working fine? (just thinking out loud here)