Passing a variable from main into a public class function? - c++

I was wondering how in this situation I can pass a variable from main into a public class function. In this situation the health variable doesn't change at all even though it should. Here's my code:
class PlayerCharacter
{
public:
void SetHealth(int Health)
{
m_health = Health;
}
int GetHealth()
{
return m_health;
}
private:
int m_health;
int m_maxhealth;
};
int main()
{
PlayerCharacter PC;
bool playing = true;
int Choice;
int v1;
int v2;
while (playing)
{
PrintMainMenu();
cout << "Set Health And Max Health" << endl;
cin >> Choice;
v1 = Choice;
cin >> Choice;
v2 = Choice;
PC.SetHealth(v1);
PC.SetMaxHealth(v2);
system("CLS");
}
return 0;
}
Is there something I'm missing here? Thanks.
edit: All of my code

From your code link, your PrintMainMenu() function is creating an entirely new Character each time. It has no relation to the one being edited in main().
You should change it to accept a Character as a reference and use that to print your stats:
void PrintMainMenu(Character& PC) {
...
}

You can try using getline (cin, input) instead of cin>> as reading directly with cin is not type safe and as far as I know, it does not remove newline character. Also, it does not perform length check. So it has been some time not to use C++ but if I remember correctly getline works better.
getline (cin, Choice);

In function void PrintMainMenu() you are creating a new Character.
You need to pass a reference on your Character from main into this function.

Related

C++ accessing vectors in classes

i am a beginner in C++ and my question is:
why my vector in a class is empty when i try to access that vector elements in another class after i added elements to that vector?
i have a class for example class1 and this class has a vector of type string and a member function which adds elements to the vector with push_back() and another member function which has an argument of type string and it returns true if the argument is in the vector or else it returns false. now if i write another class class2 and it has a vector of type string named valid and a member function named check that it reads a string from input and we have a class1 object that we can access the class1 member function to check if this input is in the vector from class1 but looks like in class2 the vector i had in class1 with elements is empty. what am i doing wrong?
here is code:
class abc{
private:
vector<string> words;
public:
void seta() {
string s;
cout << "word: ";
cin >> s;
words.push_back(s);
}
bool word_check(string a) {
for(string b : words) {
if(b == a) {
return true;
}
}
return false;
}
};
class b{
private:
vector<string> valid;
public:
void check() {
abc mlj;
string k;
cout << "Enter word to check: ";
cin >> k;
bool w = mlj.word_check(k);
while(w == false) {
cerr << "invalid input, try again: ";
cin.clear();
cin.ignore(INT_MAX, '\n');
cin >> k;
}
valid.push_back(k);
}
};
int main() {
abc vkk;
vkk.seta();
vkk.seta();
vkk.seta();
b pla;
pla.check();
}
screenshot of the output
i was expecting that i can access vector elements in class from another class
mlj is a new local object in the check method, and it contains no words. All your words were input in the main function and are stored in vkk. So you need to pass that object to check.
To do that, modify the method to receive a reference
void check(const abc & mlj)
{
string k;
cout << "Enter word to check: ";
cin >> k;
bool w = mlj.word_check(k);
// ...
valid.push_back(k);
}
Now, this will give you a compiler error, because abc::word_check is a non-const method. Let's also fix that by adding the const specifier to the method definition. While we're at it, let's accept the string as a const reference too, and also use references while iterating over the vector. This avoids unnecessary string copying.
bool word_check(const string& a) const
{
for(const string& b : words) {
if(b == a) {
return true;
}
}
return false;
}
It should be noted that this can also be achieved with std::find which is provided by the standard library in <algorithm>:
bool word_check(const string& a) const
{
return std::find(words.begin(), words.end(), a) != words.end();
}
Let's circle back to your main, and update that to call check correctly:
int main() {
abc vkk;
vkk.seta();
vkk.seta();
vkk.seta();
b pla;
pla.check(vkk); // <-- pass vkk here
}
One other thing to note is your loop in check is broken. If w is false, then the loop will never terminate because you never update w again. How about instead you do this:
while ((cin >> k) && !mlj.word_check(k))
{
cerr << "invalid input, try again: ";
cin.ignore(INT_MAX, '\n');
cin >> k;
}
if (cin)
{
valid.push_back(k);
}
This does a couple of things at once...
First, it ensures the stream has actually read a string and not entered some error state (such as end of stream). Under ordinary conditions, reading strings from standard input will not result in error bits being set, so you also don't need cin.clear().
Second, it calls word_check every time around the loop, and only enters the loop body if the check fails. After the loop, we test once again that the stream is good, and if so then it means we read a word and it passed the check.
Make these changes, and you're at least on the way to having a working program. There are other nit-picks I could make, but I may have done too many already so I'll stop! Happy coding!
In the code that you have given as an example, you have created two separate objects of the same class, each of which occupies a different space in memory and is completely independent of each other. Therefore, the mlj object is completely independent from the vkk object and nothing has been inserted in it so far. For your code to work properly I suggest you make the following change to it. That is, give the class abc to the input of class b:
class abc {
private:
vector<string> words;
public:
void seta() {
string s;
cout << "word: ";
cin >> s;
words.push_back(s);
}
bool word_check(string a) {
for (string b : words) {
if (b == a) {
return true;
}
}
return false;
}
};
class b {
private:
vector<string> valid;
public:
void check(abc mlj) {
string k;
cout << "Enter word to check: ";
cin >> k;
bool w = mlj.word_check(k);
while (w == false) {
cerr << "invalid input, try again: ";
cin.clear();
cin.ignore(INT_MAX, '\n');
cin >> k;
}
valid.push_back(k);
}
};
int main() {
abc vkk;
vkk.seta();
vkk.seta();
vkk.seta();
b pla;
pla.check(vkk);
}

What could be a better solution to calling a function recursively?

This is a simple function which will take value from user and if value is invalid then the function will call itself recursively until a valid input is provided.
#include<iostream>
using namespace std;
void getnum(){
int num;
string strnum;
getline(cin, strnum);
try{
num = stoi(strnum);
}
catch(invalid_argument &ia){
cout<<"Invalid argument\n";
getnum();
}
cout<<"\n"<<num;
}
int main(){
getnum();
return 0;
}
/*output(input: abc,abc,abc,4):
4
2494464
2494464
4201200
*/
Using the recursive approach the program is creating a new instance of the function every time an invalid argument is passed. After receiving a valid argument, function is printing multiple values(garbage values) of num due to multiple instances created.
The problem is that I want only the last value(correct one) to be printed. So I tried setting a 'flag' to control the execution of cout<<"\n"<<num.
#include<iostream>
using namespace std;
void getnum(){
int flag = 0;
int num;
string strnum;
getline(cin, strnum);
try{
flag = 1;
num = stoi(strnum);
}
catch(invalid_argument &ia){
flag = 0;
cout<<"Invalid argument\n";
getnum();
}
if(flag)
cout<<"\n"<<num;
}
int main(){
getnum();
return 0;
}
/*output(input:abc,abc,abc,4)
4 */
It solves my problem but still multiple instances are being created which I think is wastage of memory.
Is there any better way to do this without using a lot of memory(recursion)?
You get multiple outputs because you print outside "the happy path" - move printing inside the try block.
It's even clearer to put the entire "happy path" inside the try:
void getnum(){
try {
string strnum;
getline(cin, strnum);
int num = stoi(strnum);
cout<<"\n"<<num;
}
catch(invalid_argument &ia){
cout<<"Invalid argument\n";
getnum();
}
}
The idiomatic solution is to loop rather than recurse:
void getnum(){
while (true)
{
try {
string strnum;
getline(cin, strnum);
int num = stoi(strnum);
cout << "\n" << num;
return;
}
catch (invalid_argument &){
cout<<"Invalid argument\n";
}
}
}

How can I pass this structure into the available functions?

I need help passing a structure through a function to collect and print out its corresponding information. When I try and run the code below the compiler returns that I have too many arguments for the functions.
#include <iostream>
using namespace std;
int num;
void getInput();
void classBank();
struct Record
{
string fname, sname;
int marks, indexNum;
double average;
};
int main()
{
Record student;
getInput();
classBank(student);
}
void getInput()
{
cout<<"How many people are you dealing with: ";
cin >> num;
}
void classBank(struct student)
{
for(int i = 1; i < num; i++)
{
cin >> student[i].fname;
cin >> student[i].sname;
cin >> student[i].marks;
cin >> student[i].indexNum;
cin >> student[i].average;
}
}
Replace
void getInput();
void classBank();
with
void getInput();
void classBank(Record student);
EDIT:
That code won't work 'cause of several reasons:
You declare functions that use struct Record, before declaration of Record
You do not understand what keyword struct means
You pass single element (without overloaded []), not an array to the classBank
EDIT2 Typo

dynamic initalisations of c++ objects based on user input

Hey sorry for the previous Question
OK..My project is to create and run a database for a college using c++
I have to use USN which is a Unique Student Number to access the database :
So i wrote the following program :
#include<iostream>
# include<conio.h>
#include<iomanip>
#include<string.h>
#include<stdlib.h>
int checkinarray(char[],char*);
using namespace std;
class student
{
private :
int sem;
float cgpa;
char password[11];
char passwordtrial[11];
void readdata();
void checkpassword();
void createpassword();
public :
char name[50];
int roll;
void printdata();
char USN[11];
static int number;
void opendatabase();
void firsttime();
public:
student(char n[50]="NONE")
{
number++;
roll=number;
cout<<endl<<"New record under the name of "<<n<<" has been created !"<<endl;
cout<<"Roll number set for new student as : "<<roll<<endl;
cout<<"Use this Roll number for further usage"<<endl<<endl;
};
};
void student::opendatabase()
{
int ch;
cout<<"Enter your name:"<<endl;
cin>>name;
cout<<"Enter your password"<<endl;
cin>>passwordtrial;
if(!strcmp(passwordtrial,password))
{
cout<<"Do you want to read or write";
cin>>ch;
switch(ch)
{
case 0 :
readdata();
break;
case 1 :
printdata();
break;
}
}
else
cout<<"Try Again";
};
void student::readdata()
{
cout <<endl<<"Enter the name of the student : ";
cin >> name;
cout <<endl<<"Enter the semester of the student : ";
cin >> sem;
cout <<endl<<" Enter the cgpa of the student : ";
cin >> cgpa;
};
void student :: printdata()
{
cout << "The name is : " << name << endl;
cout << "The sem is : " << sem << endl;
cout << "The roll is : " << roll << endl;
cout << "The cgpa is : " << cgpa << endl;
}
void student::firsttime()
{
cout<<"Enter your name :";
cin>>name;
cout<<"Hey "<<name<<" Welcome to DBMS "<<endl;
createpassword();
};
void student::createpassword()
{
cout<<"Please enter your 6 character password.. : ";
cin>>password;
cout<<"Please Input your Data here.... :" ;
readdata();
};
int student::number=0;
int main()
{
enum status {existing,newacc,exit};
enum functi{read,update};
char entry1[40];
char entry[10];
char usn[15];
char a[1000][15];
char n[40];
int i,j=0,k;
int s=2;
cout<<endl<<"WELCOME TO COLLEGE NAME"<<endl<<"Press enter to access Database...";
getch();
cout<<endl<<"Welcome to the Main Page of our Database : "<<endl;
while(1)
{//User option
cout<<endl<<"Do you want to access an old entry : "<<endl<<"OR"<<"Create a NEW entry : ";
cin>>entry1;
if(!strcmp(entry1,"old"))
s=existing;
else if(!strcmp(entry1,"new"))
s=newacc;
else
s=exit;
switch(s)
{
case existing:
{
i=1;
break;
}
case newacc:
{ i=1;
cout<<endl<<"Enter your usn : "<<endl;
cin>>usn;
strcpy(a[j],usn);
j++;
strcpy(n,usn);
cout<<n;
student usn(n);
usn.firsttime(); //Start here!! use i to go to next loop or stay in this loop,,change name entry to usn
break;
}
default :{cout<<"Error Input";i=0;break;}
}
if(i)
continue;
cout<<endl<<"What do u want to do??"<<endl<<"Read Entries "<<endl<<"Update entries";
cin>>entry;
if(!strcmp(entry,"read"))
s=read;
else if(!strcmp(entry,"update"))
s=update;
else
s=exit;
cout<<endl<<"Enter your usn : "<<endl;
cin>>usn;
if(checkinarray(a[15],usn))
{
switch(s)
{
case read:{
usn.printdata();
break;
}
case update:{
usn.firsttime();
break;
}
default :
cout<<"Are you sure you want to exit?"<<endl<<"Press 0 to exit"<<endl<<"to back to menu press 1";
cin>>k;
break;
}
if(!k)
break;
}
else cout<<"Invalid Roll number try again!";
}
}
int checkinarray(char a[][15],char b[])
{
int len;
//Finding the length of the string :
len=(sizeof(a)/sizeof(a[0]));
//Checking Conditions for roll number:
for(int k=0;k<len;k++)
{
if(strcmp(a[k],b))
return 1;//stringcompare!!
}
return 0;
}
okay so when i run this i get the following error :
request for member 'printdata' in 'usn', which is of non-class type 'char [15]'
AND
request for member 'firsttime' in 'usn', which is of non-class type 'char [15]'
So please help me overcome this error by suggesting different ways to create and call objects based on user input
OP's problem can be reduced to the following example:
#include<iostream>
#include<string.h>
using namespace std;
class student
{
public:
student(char n[50])
{
}
};
int main()
{
char usn[15];
char n[40];
{
cin >> usn;
strcpy(n, usn);
student usn(n);
}
usn.printdata();
}
This is what is meant by a Minimal, Complete, and Verifiable example. Not everything, but everything needed to reproduce the problem. The beauty of the MCVE is it has reduced the problem to the point where all of it can fit on the screen and probably within the brain, making it easy to analyze and test.
Things to note:
There are two variables named usn
char usn[15];
is an automatic variable within main. It is visible only within main and will expire at the end of main
student usn(n);
is an automatic variable within an anonymous block within main. It is visible only within this block and will expire at the end of the block.
Annotating this block to better explain what is happening, we get
{
cin >> usn; // uses char usn[15];
strcpy(n, usn);
student usn(n); // declares a new variable named usn that replaces char usn[15];for the remainder of this block
} // student usn(n); ends right here and is destroyed.
usn.printdata(); //uses char usn[15]; which has no printdata method.
So how do we fix this?
student usn(n); must have a wider scope.
one of these two variables must change names because once student usn(n); has wider scope it will collide with char usn[15];
Lets give that a quick try.
int main()
{
char usn[15];
char n[40];
student stud(n);
{
cin >> usn;
strcpy(n, usn);
}
stud.printdata();
}
Isn't possible because there is no data in n with which we can make stud. At least not for this minimal example.
int main()
{
char usn[15];
char n[40];
student * stud;
{
cin >> usn;
strcpy(n, usn);
stud = new student(n);
}
stud->printdata();
delete stud;
}
Solves that by dynamically allocating stud so that it is no longer scoped by the braces. Unfortunately that does pick up some extra memory management woes. stud must be deleted. Added a delete, but what if printdata throws an exception and delete stud; is skipped?
int main()
{
char usn[15];
char n[40];
std::unique_ptr<student> stud;
{
cin >> usn;
strcpy(n, usn);
stud.reset(new student(n));
}
stud->printdata();
}
std::unique_ptr takes care of that. But... What about that whole database thing? Why not store stud in a list?
int main()
{
char usn[15];
char n[40];
std::vector<student> studs;
{
cin >> usn;
strcpy(n, usn);
studs.emplace_back(n); // or studs.push_back(student(n));
}
for (student & stud: studs)
{
stud.printdata();
}
}
std::vector solves both problems at once.

User input in main accessed by member functions

I have this code:
#include <iostream>
#include <string>
#include "header8.h"
using namespace std;
int main()
{
Counter test;
string input;
cout << "Enter a string\n";
getline(cin, input);
test.countcharacters();
test.countnumbers();
}
void Counter::countcharacters(){
for(unsigned int i=0; i<input.length(); i++){
if(input.at(i) == 'a'){
alphabet[0]++;
}
}
}
void Counter::countnumbers(){
for(unsigned int i;i<input.length();i++){
if(input.at(i) == '0'){
numbers[i]++;
}
}
}
My error:
When I enter my string, the value always returns 0. Any idea why?
Post your Counter class definition
As one of the comments correctly stated, I can see no way counter sees the same input var.
Edit: then based on your code the fix should be
replace in main
getline(cin, input);
with
getline(cin, test.input);
and remove
string input;
Here is my solution.
int main()
{
string input;
cout << "Enter a string\n";
getline(cin, input);
Counter test(input); // highlight
test.countcharacters();
test.countnumbers();
}
You need to call the constructor of class Counter and transfer 'input' to Counter::input (of course, you need to add a constructor with a string as the parameter). Or you can write a function as below:
void Counter::setInput(string _input)
{
this.input = _input;
}
and call this function before you start counting.