Read text file into class variable - c++ - c++

So... I tried to make an in-game shop system that reads player's account balance out of .txt file, but I've encountered this realy weird problem
So. This int works just fine. It reads data out of file, converts string to a numeric value, and prints it out.
int main() {
int money;
string cash;
ifstream playerdata;
playerdata.open("player.txt");
if (playerdata.is_open()) {
getline(playerdata,cash);
money = atoi(cash.c_str());
} else cout<<"error";
return money;
}
While this one doesn't. It always prints out that cash is equal to 0.
class Player {
int money ;
string cash;
public:
GetMoney();
int PrintMoney() {return atoi(cash.c_str());};
};
Player::GetMoney(){
int money;
string cash;
ifstream playerdata;
playerdata.open("player.txt");
if (playerdata.is_open()) {
getline(playerdata,cash);
money = atoi(cash.c_str());
playerdata.close();
} else cout<<"error";
}
int main() {
Player a;
cout<<"Your Money: "<<a.PrintMoney()<<"$";
};

Your logic in main is as follows:
Create a of type Player.
Call PrintMoney() function on a.
Your implementation of the PrintMoney function does not call the GetMoney function. In this case, cash is an empty string. Calling c_str on this empty string will result in an empty value being passed to atoi, which will return a 0.
According to the domain this appears correct. The Player doesn't yet have any money. Perhaps after declaring a you need to call a.GetMoney(), however there are other problems with your code that mean this won't quite work.
The money and cash variables in the GetMoney function will override the variables in the Player class. You should remove these.

Related

Need to find the average of the grades received by students in their group [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 months ago.
Improve this question
I created a class with students and groups. The group consists of the group name and the number of students. The student class consists of:
student name, price, and logical operation scholarship.
My main goal is to find the average of the grades received by students in their group. However, if a student's scholarship is - > false, then we don't count them. This is the main problem. I created both classes, combined them using a vector, wrote a program so that it would display the average scores of the groups, but when I turn on the program, the console only displays the name of the first group.
I want to clarify that this task is for a two-dimensional array. I just changed it to vectors to learn about the vectors (I don't know vectors well, but I will learn more about vectors in the future).
Here's my code:
#include <iostream>
#include <vector>
using namespace std;
class Student {
public:
string name;
double grade;
bool Grant;
Student() {
string is_Grant;
cin >> name >> grade >> is_Grant;
if (is_Grant == "true") {
Grant = true;
} else
Grant = false;
}
string GetName() {
return name;
}
double Get_Grade() {
return grade /** (Grant)*/;
}
};
class Group {
public:
string G_Name;
int count;
vector<Student> stud;
Group() {
cin >> G_Name >> count;
vector<Student> stud(count);
}
double GetAverage()
{
cout << "\n";
double avg = 0;
for (int i = 0; i < count; i++)
{
avg += stud[i].Get_Grade();
}
return avg / stud.size();
}
};
int main() {
int size;
cin >> size;
vector<Group> grp(size);
for (int i = 0; i < size; i++)
{
cout << grp[i].G_Name << ": Average is " << grp[i].GetAverage() << endl;
}
}
I want to know where I made a mistake. Maybe I forgot to add something?
First, I was using Void GetAvg() instead of a string. At that time, when I only typed in the number of inputs, the program stopped there.
I also tried creating a bool value as a separate function, but it wouldn't output either.
Most importantly, I want to know why the program doesn't find the average value.
So your code is super weird and I'm not sure it can ever work, but there is one obvious error
Group() {
cin >> G_Name >> count;
vector<Student> stud(count);
}
that should be
Group() {
cin >> G_Name >> count;
vector<Student> s(count);
stud = s;
}
Your version creates a local variable called stud which is a vector with the given size, but that has nothing to do with the stud that is a member variable in the Group class. My version uses a different name and then assigns that variable to stud.
This is still weird code, the code I originally wrote in the answer was the more natural
Group() {
cin >> G_Name >> count;
vector<Student> s(count);
stud.resize(count);
}
but this code doesn't work because your strange constructors. This version of the code only creates one Student which is then copied to fill in the vector. So you would end up with count identical students. More on this in the last paragraph.
The reason for your error is that when you call GetAverage you have some value for count but because of the bug the size of stud is still zero, so you are accessing that vector out of bounds and that (probably) is what is crashing your code.
And that brings up another issue with your code. One of the reasons vectors are superior to arrays is that vectors know their own size, and so variables like count are redundant, just query the vector for it's size. Rewriting your code to take advantage of that gives you something like this
class Group {
public:
string G_Name;
vector<Student> stud;
// no count in group
and this
Group() {
int count; // count is now a local variable
cin >> G_Name >> count;
vector<Student> s(count);
stud = s;
}
and this
double GetAverage()
{
cout << "\n";
double avg = 0;
for (int i = 0; i < stud.size(); i++) // get the count from the vector
{
avg += stud[i].Get_Grade();
}
return avg / stud.size();
}
But the elephant in the room is the way you do data input in your constructors. Don't do that. It means that every time you declare a variable the program is going to pause and ask the user for input. It also means that every student you do want to create has to be created with the default constructor, which is why my resize code doesn't work. Think about how restricting that is going to be going forward.

Why is the Output is skipping statement of gets(&char*)

In the code below I have a class called Market. With the data members and functions as shown. When the function shopkeeper(market &m , int i) is called , The compiler executes the the printing of "Name" and "Price" without taking the Name from user by gets().
class market
{
public:
char item;
double price, tax, total;
public:
market()
{
char* item;
price=0;
tax=0;
}
void shopkeeper(market &m, int i)
{
cout<<" Item number "<<i<<"\n ";
cout<<" ----------- "<<"\n";
cout<<"Name ";
gets(&(m.item));
cout<<" Price "<<endl;
cin>>m.price;
cout<<" Tax "<<endl;
cin>>m.tax;
}
The output us as follows:
item is a single char. If you read documentation of gets, that function receives a pointer to buffer you have to allocate, big enough to fit input, or an Undefined Behavior would happen.
Also, gets is a function which should no longer be used in C++. It also was removed from recent versions of language. You should use std::string and read it from std::cin like everything else.

Sorting, adding, removing, and printing objects in C++

I initialized objects in my code using a house number (int) and the person's name (string). This part of my code works and it displays the house number and person correctly.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//AddressBook class definition
class AddressBook
{
public:
//Declare a constructor that has one parameter for each data member
AddressBook(int, string);
//Declare a set method for house number
void setHouseNum(int);
//Declare a get method for house number
int getHouseNum();
//Declare a set method for name
void setName(string);
//Declare a get method for name
string getName();
void displayAddressBook();
private:
//Declare a int data member for house number
int houseNum;
//Declare a string data member for name
string name;
};
// constructor
AddressBook::AddressBook(int num, string personName)
{
setHouseNum(num);
setName(personName);
}
void AddressBook::setHouseNum(int num)
{
houseNum = num;
}
int AddressBook::getHouseNum()
{
return houseNum;
}
void AddressBook::setName(string personName)
{
name = personName;
}
string AddressBook::getName()
{
return name;
}
void AddressBook::displayAddressBook()
{
cout << getHouseNum() << " " << getName() << endl;
}
int main()
{
AddressBook addressBook(3, "Jim");
addressBook.displayAddressBook();
AddressBook addressBook2(5, "Bob");
addressBook2.displayAddressBook();
AddressBook addressBook3(2, "Jeb");
addressBook3.displayAddressBook();
string command;
cout << "Available Commands Are:" << endl;
cout << "Add, Remove, Sort, Print" << endl;
return 0;
}
Output:
3 Jim
5 Bob
2 Jeb
Available Commands Are:
Add, Remove, Sort, Print
The next part is what I'm having trouble with. I'm supposed to read the user input to see what they want to do and perform the operations listed above. So, if they say Add, and then enter "2 Jeb", the code has to say 2 already exists. If it doesn't exist, it has to add it as an object and print the entire list back out.
I know that you can use getline(cin,name) to get the name from the user but I do not know how to implement that in my code to do what I want it to. Once I get the user input string, how do I create an object with it? Also, how do you read an integer the user inputs into an object because I read that getline works for strings and not integers.
Once I read the integer and string input from the user, how do I check if the house number already exists in my objects? If I can get some help with just these two things I can figure the rest out.
Thank you.

How would I go on as to "return" string arrays between functions?

Hey so I was experimenting what I knew and realized when I tried passing a string value with return it wasn't supported, any idea? Sorry if my code is noob style (I only have 2 months of experience), I was planning on splitting the code between functions but I can't seem to do it because returning my array of strings cant be done with return :( Here's the code:
#include <iostream>
#include <math.h>
#include <sstream>
using namespace std;
int itemlist=0;
int c=0;
int r = 0;
int itemlistdec()
{
cout<<"How many items would you like to input?";
cin>>itemlist;
return itemlist;
}
int main() {
itemlistdec();
string item[4][itemlist];//declares item and that columns equal to itemlist whose content is declared right above
for (int c=0;c<itemlist;c++)
{
for (int r=0;r<3;r++) //DETERMINES WHERE EACH RECORD GOES
{
if (r==0)
{
cout<<"Please enter the name of the item ";
}
if (r==1)
{
cout<<"Please input the buying price\n";
}
if (r==2)
{
cout<<"Please input the selling price\n";
}
cin>>item[r][c];
}
}
int calc[3][itemlist];//declaring calc and itemlist
for (int r = 0;r<itemlist;r++)
{
istringstream(item[1][r])>>calc[0][r]; //TAKES BUYING PRICE INTO INT ARRAY FOR CALCULATION
}
for (int r = 0;r<itemlist;r++)
{
istringstream(item[2][r])>>calc[1][r]; //TAKES SELLING PRICE INTO INT ARRAY FOR CALCULATION
}
for (int fart = 0;fart<itemlist;fart++)
{
calc[2][fart] = calc[1][fart] - calc[0][fart]; //REPEATS CALCULATION FOR PROFIT UNTIL ITEMLIST IS REACHED
}
for (int r = 0;r<itemlist;r++)
{
stringstream ss;
ss<<calc[2][r]; //CONVERTS BOTH PROFIT VALUES INTO STRINGS
item[3][r] = ss.str();
}
cout<<"______________________________________________\n"; //DISPLAYS OUTPUT IN TABLE FORM
cout<<"Item\t\tBuying Price\t\tSelling Price\t\tProfit\n";
for (int c=0;c<itemlist;c++)
{
for (int r=0;r<4;r++)
{
cout<<item[r][c]<<"\t\t";
if (r==1)
{
cout<<"\t";
}
if (r==2)
{
cout<<"\t";
}
if (r==3)
{
cout<<"\n";
}
}
}
return 0;
}
I think you can use vector, it's very powerful. Like that:
std::vector<std::vector<std::string> > mySecondVector;
std::vector<std::string> myFirstVector;
myFirstVector.push_back("MyString");
mySecondVector.push_back(myFirstVector);
mySecondVector[i][j]; // to access
And for add, access to an element watch on http://www.cplusplus.com/reference/vector/vector/
Returning an array is a bit goofy. you have to return it as a pointer, and as soon as you do that you lose all size information. You have this handled by itemlist hanging around as a global variable, but global variables impose their own set of limitations. For one, you can never have more than one of these arrays (unless they are all the same size) because multiple arrays would be storing their length in the same spot.
First you have to flip the orientation of the array to get the constant size on the right-most index. Frankly because of locality (all of the data with respect to one item is in the same memory region, so if you load one part of an item into cache you probably load all of it. This almost always results in a much faster program) it's probably better that way, anyway. Then you've probably noticed you can't just return string[][] or anything that looks like it without the compiler barking at you, so you have to play games defining custom data types that you can return.
typedef string (*arrayPtr)[4];
Now you could try
arrayPtr itemlistdec()
{
cout << "How many items would you like to input?";
cin >> itemlist;
string item[itemlist][4];
//load the array
return item;
}
And itemlist knows how big the array is, but you get a new snag. Item goes out of scope on you and is no longer valid. Even more fun, string item[itemlist][4]; isn't even legal C++ because itemlist isn't a constant value. It works as a convenience in some C++ compilers, but not all.
So how about this? Dynamic allocation of the array will make it outlive itemlistdec, but now you'll have to delete the array manually when you are done with it.
arrayPtr itemlistdec()
{
cout << "How many items would you like to input?";
cin >> itemlist;
arrayPtr item = new string[itemlist][4];
//load the array
return item;
}
Now we've got something that works. We can make it a bit more readable (and less at the same time, because a reader has to track down just what an array is in order to know how to use it) by
typedef string (array)[4];
typedef array (*arrayPtr);
arrayPtr itemlistdec()
{
cout << "How many items would you like to input?";
cin >> itemlist;
arrayPtr item = new array[itemlist];
//load the array
return item;
}
This does not extend to variable length on both dimensions or if you absolutely must have the constant on the inside index. For that case you need this bastich:
string ** itemlistdec()
{
cout << "How many items would you like to input?";
cin >> itemlist;
string** item = new string*[4]; // 4 can be any number, but you also have to
// use it in place of 4 in the for loop
for (size_t index = 0; index < 4; index++)
{
item[index] = new string[itemlist];
}
//load the array
return item;
}
Doable, but you now have picked up a bunch of memory management duties. All of the allocated memory must be released with delete[]. In the string ** case, you have to run through the left-most index and delete[] all of the right-most arrays before deleting the left-most.
You can eliminate this with vector<vector<string>>, but in this case it's ugly. Great trick, but doesn't fit the overall program goal.
vector<vector<string>> itemlistdec()
{
int itemlist;
cout << "How many items would you like to input?";
cin >> itemlist;
vector<vector<string>> item(4, vector<string>(itemlist));
for (int c=0;c<itemlist;c++)
{
cout<<"Please enter the name of the item ";
cin>>item[0][c];
cout<<"Please input the buying price\n";
cin>>item[1][c];
cout<<"Please input the selling price\n";
cin>>item[2][c];
}
return item;
}
Note I'm returning the local vector and counting on move semantics to move the vector on return rather than copying it. Also note that you don't need a global itemlist anymore because the vector knows how big it is. You can even add stuff to it later if you want. And also note I ditched the inner for loop on the input. It's not needed.
This works better than the array options, but I still don't like it. Item is calling out for its own class so we can take advantages of the goodies that object oriented programming brings. We can also the correct data types for all of the member variables. That way we can catch bad input as the user enters it and get rid of an extra integer array used by the calculation.
class Item
{
public:
void read(istream & in)
{
// ignoring possibility of total failure of cin here.
cout<<"Please enter the name of the item ";
in >> name;
cout<<"Please input the buying price\n";
while (!(in >> buyPrice)) // loop until we read an integer from the user.
{
in.clear();
cout<<"Invalid. Please input the buying price\n";
}
cout<<"Please input the selling price\n";
while (!(in >> sellPrice))
{
in.clear();
cout<<"Invalid. Please input the selling price\n";
}
return in;
}
// calc logic method goes here.
// output method goes here.
private:
string name;
int buyPrice; // no screwing around with the calc array. numbers are
//read in as numbers or the input fails
int sellPrice;
};
vector<Item> itemlistdec()
{
int nrItems = 0;
cout << "How many items would you like to input?";
cin >> nrItems;
vector<Item> itemlist(nrItems);
for (Item& item : itemlist)
{
item.read(cin);
}
return itemlist;
}
Note I'm not checking validity of all input, just that valid integers were used. Probably sufficient, but ehhhh.... I have accidentally closed stdin by mistake. Not a fun thing to debug. Anyway, you have worse problems if stdin is going down.

Creating an employee class

I am attempting to write the following:
1) Write the class definition for a class named Employee with name and salary as employee objects. The class contains two member functions: the constructor and a function that allows a program to assign values to the data members.
2) Add two member functions to the Employee class. One member function should allow any program using an employee object to view the contents of the salary data member. The other member function should allow the program to view the contents of the employee name data member.
3) Add another member function to the Employeeclass. The member function should calculate an employee objects new salary, based on a raise percentage provided by the program using the object. Before calculating the raise, the member function should verify that the raise percentage is greater than or equal to zero. If the raise percentage is less than zero, the member function should display an error message.
4) Write a main function that will create an array of employee objects, assign
values to the objects, display the names and current salaries for all objects,
ask user for the raise percentage and then calculate and display new salaries
for all objects.
I have attempted this with the following code:
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class EMPLOYEE
{
public:
EMPLOYEE();//
EMPLOYEE(string name, int salary);//
public:
string name;//name to be input
int salary;//salary to be input
public:
int enter_values();
int output_values();
int NEW_SALARY( int percentage_raise);
};
//default constructor
EMPLOYEE::EMPLOYEE()
{
name = "";
salary = 0;
}
//constructor with name/salary variables
EMPLOYEE::EMPLOYEE(string NAME, int SALARY)
{
name= NAME;
salary= SALARY;
}
//name and salary to be input...
int EMPLOYEE::enter_values()
{ cout<<"Enter name and salary: ";
cin>> name;
cin>>salary;
}
//output
int EMPLOYEE::output_values()
{ cout<<"Name: "<<name<<endl;
cout<<"Salary: "<<salary<<endl;
}
//
int EMPLOYEE::NEW_SALARY(int percentage_raise)
{
EMPLOYEE updated_salary;
if ( percentage_raise >= 0){salary= salary *(percentage_raise/100);
}
else if(percentage_raise< 0)
{ cout<<"Error Message"<<endl;
}
return percentage_raise;
}
int main()
{
EMPLOYEE employees[100];
EMPLOYEE.NEW_SALARY();
int percent= 0;
int i;
for(i =0 ;i<100 ; i++)
{ employees[i]=EMPLOYEE();
employees[i].enter_values();
employees[i].name;
employees[i].salary;
employees[i].output_values();
cout<<"How much should the salary be raised by?"<<endl;
cin>>percent;
cout<<EMPLOYEE.name<<"'s new salary is "<<percentage_raise<<endl;
}
}
However, I cannot access the parts I need to store the information into the array in the main function, nor can I apply the percentage raise when the program prompts the user.
I'm pretty sure I have syntax errors which I am unaware of. I'm not asking for someone to do everything for me, but I would appreciate a steer in the right direction. I don't quite understand classes and how to call them into different parts of a program. Thank you for your time.
You have almost everything in good order.
Things to fix:
The line
if ( percentage_raise >= 0){salary= salary *(percentage_raise/100);
will set salary to zero unless percentage_raise is greater than 100. That's because the expression (percentage_raise/100) will be an integer division and will evaluate to zero, unless pecentage_raise is greater than 100.
You can fix it with:
if ( percentage_raise >= 0)
{
int raise = (salary*percentage_raise)/100;
salary += raise;
}
The line
EMPLOYEE.NEW_SALARY();
is going to produce a compiler error since there is no object named EMPLOYEE.
You can safely remove that line. It's not serving any purpose.
You are missing a call to set the percentage raise after you read the input. You need the line
employees[i].NEW_SALARY(percent);
immediately after you read percent.
The following line is incorrect.
cout<<EMPLOYEE.name<<"'s new salary is "<<percentage_raise<<endl;
since there is no object named EMPLOYEE. You can replace it with:
cout<<employees[i].name<<"'s new salary is "<<employees[i].salary<<endl;
class Employee
{
public:
Employee();
int salary;
};
Employee::Employee() { salary = 10; }
int main()
{
Employee joe;
std::cout << "Joe Salary: " << joe.salary << std::endl;
joe.salary = 15;
std::cout << "Joe New Salary: " << joe.salary << std::endl;
}
Usually, you will want your data members to be private and use an accessor method to provide the values of the data members which, again, should be private.