I am new programming and C++. I am trying to create a Roster of Person objects using an array and then printing the attributes of the People in the Roster.
When I attempt to add a Person to the personArray, I am getting an
Exception = EXC_BAD_ACCESS (code=1, address=0x0).
I think this has to do with the scope of my personArray but I can't seem to figure it out.
Here is the code I am using:
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
class Person
{
public:
Person(string name, int age);
string getName() {
return name;
}
void setName(string n) {
name = n;
}
int getAge() {
return age;
}
void setAge(int a) {
age = a;
}
private:
string name;
int age;
};
class Roster {
public:
void addToPersonArray(string name, string age) {
Person person(name, stoi(age));
personArray[personCount] = &person;
}
void printPersonArray() {
for (int i = 0; i < 5; i++)
cout << personArray[i]->getName() << '\t' << personArray[i]->getAge() << '\n';
}
private:
Person *personArray[5];
int personCount = 0;
};
int main() {
const string studentData[] = {"Dan,45", "Mark,33", "Mary,22",
"April,17", "Jill,22"};
Roster roster;
stringstream ss(studentData[0]); // just testing the first entry
vector<string> result;
while (ss.good()) {
string substr;
getline(ss, substr, ',');
result.push_back(substr);
}
roster.printPersonArray();
}
The problem is here:
void addToPersonArray(string name, string age) {
Person person(name, stoi(age));
personArray[personCount] = &person;
}
person is a local variable in the member function addToPersonArray(), which will be destroyed after the function scope.
Hence, storing the address of a local variable(and trying to accessing it latter in printPersonArray()) will give you, nothing but an undefined behavior.
You are lucky that your programme got the exception.
One more thing to note that, you are not actually using your roster to test the program. Instead, all you do is parsing and saving to result vector. You can add this after the while loop, to make it actually work.
if (result.size() == 2) {
roster.addToPersonArray(result[0], result[1]);
}
Suggestion: Since you have a fixed array size, you probably wanna do it with std::array<Person, 5> or with std::vector<Person> by reserving the memory for 5 Person in the c'tor of Roster.
See a sample output: https://wandbox.org/permlink/tAGqqnhCfwz1wPrH
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
class Person {
public:
Person(const std::string& name, int age): name(name), age(age) {}
std::string getName()const { return name; }
void setName(const std::string& n){ name = n; }
int getAge()const { return age; }
void setAge(int a) { age = a; }
private:
std::string name;
int age;
};
class Roster {
public:
Roster() { personArray.reserve(5); } // reserve some memory
void addToPersonArray(const std::string& name, const std::string& age) {
personArray.emplace_back(name, stoi(age));
}
void printPersonArray() {
// use range loop, which will assure, access what you have.
for (const Person& person: personArray)
std::cout << person.getName() << '\t' << person.getAge() << '\n';
}
private:
std::vector<Person> personArray;
//int personCount = 0; --------------> no need anymore
};
int main() {
std::array<std::string,5> studentData{ "Dan,45", "Mark,33", "Mary,22", "April,17", "Jill,22" };
Roster roster;
for(const std::string& str: studentData)
{
std::stringstream ss(str);
std::vector<std::string> result;
while (ss.good()) {
std::string substr;
std::getline(ss, substr, ',');
result.emplace_back(substr);
}
if (result.size() == 2) {
roster.addToPersonArray(result
[0], result[1]);
}
}
roster.printPersonArray();
return 0;
}
Output:
Dan 45
Mark 33
Mary 22
April 17
Jill 22
In addition to storing pointers to local variables in your addToPersonArray() function, your main() function does not add any entries to the personArray.
Instead, main creates a Roster object, and after some code that doesn't affect anything with Roster, you go straight into calling roster.printPersonArray, which does this:
void printPersonArray()
{
for (int i = 0; i < 5; i++) // <-- This will loop for all 5 entries
cout << personArray[i]->getName() << '\t' << personArray[i]->getAge() << '\n';
}
Since personArray was never initialized to contain valid pointers to Person objects, that loop will cause undefined behavior.
The issue is that you have a personCount member variable, but fail to make use of it to control how many valid entries there are in the array. The loop should have been written as below:
void printPersonArray()
{
for (int i = 0; i < personCount; i++)
cout << personArray[i]->getName() << '\t' << personArray[i]->getAge() << '\n';
}
In addition to the storage of pointers to local variables, your Roster::addToPersonArray() doesn't check if personCount is greater than 4, thus this is another place in your code where you failed to use personCount to control how many Person objects are being referenced.
Related
I am trying to make an object as a parameter for my add() function in this code:
class EnterInfo
{
protected:
string name;
int age;
string birthmonth;
public:
EnterInfo()
{
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
public:
CourseInfo()
{
}
CourseInfo(string t)
{
title = t;
}
void add()
{
}
};
int main()
{
EnterInfo s1;
CourseInfo c1;
s1 = EnterInfo("Sand", 20, "Jan");
c1 = CourseInfo(" x Records");
}
I want the add() function to gather all the data from the object "s1" and compact it into an array that I can access later. I could add, remove, or edit the data moving forward or even maybe make a new object "c2" which contains "y records" with the same s1 values ("sand", 20, "Jan"), however, I have no idea how to implement this in code.
c1.add(s1); // assume s1 (EnterInfo): Sand 20 Jan
c1.add(s2); // assume s2 (EnterInfo): Paul 23 Aug
this is the code I want to work with. I don't know how to make it work though. The end game would be this
c1.print();
output:
x records
Sand 20 Jan
Paul 23 Aug
create a vector of EnterInfo objects and put it in CourceInfo class. The code below does what you need:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class EnterInfo
{
public:
string name;
int age;
string birthmonth;
EnterInfo()
{
name = "";
age = 0;
birthmonth = "";
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
vector<EnterInfo> info_vec;
public:
CourseInfo()
{
title = "";
}
CourseInfo(string t)
{
title = t;
}
void add(const EnterInfo enterInfo)
{
this->info_vec.push_back(enterInfo);
}
void print() {
cout << this->title << endl;
for (const auto& it : this->info_vec) {
cout << it.name << " " << it.age << " " << it.birthmonth << endl;
}
}
};
int main()
{
EnterInfo s1("Sand", 20, "Jan");
EnterInfo s2("Arash", 21, "Feb");
CourseInfo c1(" x Records");
c1.add(s1);
c1.add(s2);
c1.print();
}
Side notes:
1- It's better to assign default values to the members of your class in the constructor.
2- I changed the access level of your EnterIndo members into public in order to use them in add function but the standard way is to set them to private and create getters and setters for them.
Research about std::vector and get/setters if you are not familiar with them.
I am writing some C++ code to create an item of a class i have created inside a vector of another class. I seem to be able to create the items inside the vector but when i try to read a variable of the item inside the vector i get the error
Exception thrown: read access violation.
_Right_data was 0x8.
inside the document xstring.
I think it might have something to do with me not actually creating each team inside the vector.
the code i have written that is relavent is
for (int x = 1; x <= mainLeague.getNumTeams(); x++) {
std::cout << "please enter the name of team " << x << ":";
std::getline(std::cin, currLine);
parsed = parseText(currLine, &posResponsesTeamNames);
if (parsed == 2) {
prepForEnd();
return 1;
}
else if (parsed == 0) goto enterTeamNames;
mainLeague.createTeam(currLine);
}
std::cout << mainLeague.getName(5);
}
#pragma once
#include "team.h"
#include <string>
#include <vector>
#include <iostream>
class league
{
std::vector<team*> teams;
int numTeams, numInitTeams = 0;
const float sysCon = 0.5;
public:
league(int a);
int getNumTeams();
void initVector(int numTeams);
void createTeam(std::string name);
std::string getName(int num);
};
void league::createTeam(std::string name)
{
if (numInitTeams < teams.size()) {
team currTeam = team::team(name);
teams.at(numInitTeams) = &currTeam;
numInitTeams;
}
else {
std::cout << "error max amount of teams already created";
}
}
#pragma once
#include<string>
class team
{
float RD;
int rating;
std::string name;
public:
team(std::string name);
team();
std::string getName();
};
std::string team::getName()
{
return team::name;
}
Im playing around with a tiny c++ project. Im trying to add an object of person (from my Person class) into an Array.
But when i run my code it tells me that Person struct is NULL.
However, it also sais that my person got a name and an adress, so it doesnt seem like its null?
I have a Person class:
.h
{
public:
std::string name;
std::string adress;
Person() = default;
Person(std::string name, std::string adress);
void Print();
~Person();
};
.cpp
#include "Person.h"
#include <iostream>
#include <string>
Person::Person(std::string name, std::string adress)
{
this->name = name;
this->adress = adress;
}
void Person::Print()
{
std::cout << "Namn: " << name << ". Adress: " << adress << std::endl;
}
Person::~Person()
{
}
I Have an PersonRegister class:
.h
#include "Person.h"
class PersonReg
{
public:
int indexInt = 0;
int maxSize = 50;
Person *person;
PersonReg() = default;
PersonReg(int maxSize);
void AddPerson(Person *person);
void PrintPersons();
void DeletePerson(Person *person);
~PersonReg();
};
.cpp
#include <string>
#include "Person.h"
PersonReg::PersonReg(int maxSize)
{
this->maxSize = maxSize;
person = new Person[maxSize];
}
void PersonReg::AddPerson(Person *person)
{
person[indexInt++] = *person;
}
void PersonReg::PrintPersons()
{
for (Person* personPtr = person; personPtr != person + maxSize; ++personPtr)
{
personPtr->Print();
}
}
void PersonReg::DeletePerson(Person *person)
{
if (person != nullptr)
{
for (Person *personPtr = person; personPtr != person + maxSize; ++personPtr)
{
personPtr->name = "NO NAME";
}
}
}
PersonReg::~PersonReg()
{
delete[]person;
}
When I execute it, I get the Error:
Exception thrown at 0x7AFC3729 (vcruntime140d.dll) in Labb3_c++.exe: 0xC0000005: Access violation writing location 0xCCCCCCCC.
But in the output, I can see that person name and adress has values.
Im reading to PersonReg from a text-file like this. This is my main:
#include "pch.h"
#include <iostream>
#include <fstream>
#include "Person.h"
#include "PersonReg.h"
bool ReadReg(PersonReg& reg, std::string fileName)
{
std::string line;
std::ifstream myfile(fileName);
if (myfile.is_open())
{
while (getline(myfile, line))
{
while (line.length() == 0 && getline(myfile, line))
;
std::string name(line);
std::string adress;
getline(myfile, adress);
reg.AddPerson(&Person(name, adress));
}
myfile.close();
return true;
}
else {
std::cout << "Unable to open file";
return false;
}
}
void Test1(Person* person, PersonReg personReg)
{
ReadReg(personReg, "PersonExempel.txt");
personReg.PrintPersons(); std::cout << "\n\n";
personReg.DeletePerson(person);
}
int main()
{
Person *person = new Person();
PersonReg personReg = PersonReg();
Test1(person, personReg);
delete person;
return 0;
};
Im supposed to add a person in my personArray.
Then print the person with a simple print function.
And then delete the Person again.
EDIT: Sorry for long post but Im not sure where the problem is located (besides the memory). Im a totally beginner is C++ so it sure can look like a mess!
Take a look at this code:
void PersonReg::AddPerson(Person *person)
{
person[indexInt++] = *person;
}
You are using person on both left and right side. But what is person here? Is it the passed argument? Is it the member variable of the class?
It seems that you want the LHS to be the member variable while you want the RHS to be the passed argument. But how do you expect the compiler to know that?
You can use this->person to explicit refer to the member variable. However, I'll recommend a renaming of the member variable to something like personArray or a renaming of the argument like: void PersonReg::AddPerson(Person *pers).
Further:
PersonReg personReg = PersonReg();
Shouldn't this be
PersonReg personReg = PersonReg(42);
^^
some number
so that you call the intended constructor, i.e. the constructor that calls new and reserve memory for the array.
All that said - I'll recommend that you use std::vector instead of an array allocated using new
First of all the maxSize is not getting the value of 50. That's why there is not object Person. You should delete the PersonReg() = default; and keep the other constructor like this PersonReg(int maxSize=50);
As #PeterT mentioned you had a problem in this function. this-> should fix it:
void PersonReg::AddPerson(Person *person)
{
this->person[indexInt++] = *person;
}
I corrected a few other things. PrintPersons could be this way and it works:
void PersonReg::PrintPersons()
{
for(int i=0; i<indexInt; i++){
person[i].Print();
}
}
Also on the DeletePerson function I cannot understand what exactly you want to do. If you want to delete a spesific person you should change the function to this:
void PersonReg::DeletePerson(Person *person)
{
if (person != nullptr)
{
for(int i=0; i<indexInt; i++){
if(this->person[i].name==person->name&&this->person->adress==person->adress){
this->person->name="NO NAME";
this->person->adress="NO ADDRESS"; //or something like that.
}
}
}
}
I tested all of these and they work. I hope I helped.
for example lets have a class or struct name Employee with two constructors, a default constructor and a constructor with parameters two strings and an int. why doesn't the following code work?
Employee *employees = (employee*) malloc(sizeof(Employee)*10);
let's say we have an array, size 10, of type string for first name, last name, and one of type int for salary. how to initialize the data members of each object class using the constructor with the parameters?
for (int i = 0; i < 10; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
I've been trying to do this for a few days now but wasn't successful. Also, can anyone tell how to do this using c++'s new and delete operator? and also is there a way this can be done using vectors?
Thank you
header file
class employee{
std::string firstname;
std::string lastname;
int salary;
public:
employee(std::string, std::string , int);
employee();
void setFirst(std::string);
void setLast(std::string);
void setSalary(int);
std::string getFirst();
std::string getLast();
int getSalary();
};
employee::employee(std::string x, std::string y, int z)
{
setFirst(x);
setLast(y);
setSalary(z);
}
void employee::setFirst(std::string x)
{
firstname = x;
}
void employee::setLast(std::string y)
{
lastname = y;
}
void employee::setSalary(int z)
{
salary = z > 0 ? z : 0;
}
std::string employee::getFirst()
{
return firstname;
}
std::string employee::getLast()
{
return lastname;
}
int employee::getSalary()
{
return salary;
}
.cpp file
#define MAX 20
using namespace std;
int main(int argc, char* argv[])
{
int n = 1;
cout << "number of employees: ";
cin >> n;
string firstname[MAX];
string lastname[MAX];
double salary[MAX];
float raise[MAX];
for (int i = 0; i < n; i++)
{
cout << "Employee " << i + 1 <<endl;
cout << "-----------\n";
cout << "First Name: ";
cin >> firstname[i];
cout << "Last Name: ";
cin >> lastname[i];
cout << "Monthly Salary: ";
cin >> salary[i];
salary[i] *= 12;
cout <<"Yearly percentage raise (e.g 10% or 0%): ";
scanf("%f%%", &raise[i]);
salary[i] *= (((raise[i])/100.00) + 1);
puts("\n");
}
employee *employees = (employee*) malloc(sizeof(employee)*10);
for (int i = 0; i < n; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
cout << "TESING USING GET FUNCTIONS" << endl;
cout << "---------------------------\n\n";
for (int i = 0; i < n; i++)
{
cout << "Employee " <<i +1<< endl;
cout <<"-----------\n";
printf("First Name: %s", employees[i].getFirst().c_str());
printf("\nLast Name: %s",employees[i].getLast().c_str());
printf("\nYearly Salary: %d\n\n", employees[i].getSalary());
}
}
If you have an array of Employee instances and Employee is not POD (http://en.wikipedia.org/wiki/POD) you need to allocate memory from the stack using the operator new:
Employee* employees = new Employee[10];
And for having this working:
for (int i = 0; i < 10; i++)
{
employees[i] = Employee(firstname[i], lastname[i], age[i]);
}
you need to implement the operator= in your Employee class:
Employee& operator=(const Employee& src)
{
_firstname = src._firstname;
_lastname = src._lastname;
_age = src._age;
return *this;
}
If this looks like your Employee class:
class Employee
{
std::string first_name;
std::string last_name;
// other members and functions ...
};
Then using malloc() to create 10 of these is a complete and utter failure. The reason why is that yes, you allocated memory using malloc(), but that's all you did. You didn't construct 10 Employee objects. Those std::string members need to be constructed, not merely have memory allocated. So with that call to malloc() you have 10 fake Employees that were "created", and as soon as you attempt to do anything with one of them, then boom goes your program.
Do research on POD and non-POD types. You cannot treat non-POD types (as the class above is non-POD) as you would a POD type. For a non-POD type, the instance must be "officially" constructed, (the constructor must be invoked).
On the other hand, malloc() knows nothing concerning C++ and what is required to create an object correctly via construction. All malloc (and calloc, and realloc) knows is to allocate bytes and return a pointer to the allocated space.
Use a vector instead, it's resizable, it's easier to manage, and as Grady stated in his comment, it's also generally not good practice to use malloc in C++ code (although it's possible). Maybe do something that looks like this:
#include <vector>
...
int size = 10;
std::vector<Employee *> employees;
for(int i = 0; i < size; i++)
{
//as far as pulling in your data, that depends on where it's coming from
Employee *temp = new Employee(...);
employees.push_back(temp);
}
I'm rusty on my C++ but this should work.
Try this way:
#include <iostream>
class Employee
{
std::string m_firstname;
std::string m_lastname;
int m_age;
public:
Employee()
{
m_firstname=m_lastname="";
m_age=0;
}
void setFirstName(std::string firstname)
{
m_firstname=firstname;
}
void setLastName(std::string lastname)
{
m_lastname=lastname;
}
void setAge(int age)
{
m_age=age;
}
void displayEmp()
{
std::cout<<m_firstname;
std::cout<<m_lastname;
std::cout<<m_age;
}
};
int main()
{
std::string fname;
std::string lname;
int age;
Employee *employee = new Employee[10];
Employee *employeeptr=employee;
for(int i=0;i<10;i++)
{
std::cin>>fname;
std::cin>>lname;
std::cin>>age;
employeeptr->setFirstName(fname);
employeeptr->setLastName(lname);
employeeptr->setAge(age);
employeeptr++;
}
employeeptr=employee;
for(int i=0;i<10;i++)
{
employeeptr->displayEmp();
employeeptr++;
}
delete []employee;
return 0;
}
I'm just starting to learn object oriented programming in C++ and am having issues figuring out how to print an object that is stored inside an array. From what I know, I want to just try to try and go through the array and print out each employee object, how because objects are different than variables like int and double I'm sure it's causing a problem. Is my logic wrong, or is it just syntax? Here is my code:
Header:
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include <string>
using namespace std;
class Employee
{
private:
string name;
string idNumber;
string department;
string position;
int yearsWorked;
public:
Employee();
Employee(string, string);
Employee(string, string, string, string, int);
void setName(string);
void setIdNumber(string);
void setDepartment(string);
void setPosition(string);
bool setYearsWorked(int);
string getName()const;
string getIdNumber()const;
string getDepartment()const;
string getPosition()const;
int getYearsWorked()const;
};
#endif
Implementation:
#include "Employee.h"
using namespace std;
Employee::Employee()
{
string name = "";
string idNumber = "";
string department = "";
string position = "";
int yearsWorked = 0;
}
Employee::Employee(string nm, string id)
{
string name = nm;
string idNumber = id;
string department = "";
string position = "";
int yearsWorked = 0;
}
Employee::Employee(string nm, string id, string dpt, string pos, int years)
{
string name = nm;
string idNumber = id;
string department = dpt;
string position = pos;
int yearsWorked = years;
}
void Employee::setName(string nm)
{
name = nm;
}
void Employee::setIdNumber(string id)
{
idNumber = id;
}
void Employee::setDepartment(string dpt)
{
department = dpt;
}
void Employee::setPosition(string pos)
{
position = pos;
}
bool Employee::setYearsWorked(int years)
{
if (years >= 0)
{
yearsWorked = years;
return true;
}
else
return false;
}
string Employee::getName()const
{
return name;
}
string Employee::getIdNumber()const
{
return idNumber;
}
string Employee::getDepartment()const
{
return department;
}
string Employee::getPosition()const
{
return position;
}
int Employee::getYearsWorked()const
{
return yearsWorked;
}
Main:
#include <iostream>
#include <iomanip>
#include "Employee.h"
using namespace std;
const int SIZE = 3;
int main()
{
Employee emp1("Jenny Jacobs", "JJ8990", "Accounting", "President", 15);
Employee emp2("Myron Smith", "MS7571", "IT", "Programmer", 5);
Employee emp3("Chris Raines", "CR6873", "Manufacturing", "Engineer", 30);
Employee employees[SIZE] = {emp1, emp2, emp3};
for (int i = 0; i < SIZE; i++)
{
cout << employees[i] << endl;
}
system("PAUSE");
return 0;
}
Add this:
std::ostream& operator<<( std::ostream& stream, Employee const& emp )
{
return (stream << emp.getName());
}
Modify as needed.
General comments:
Do not place using namespace std; in the global namespace in a header. Keep in mind that the standard library defines very common names like distance. Which can easily lead to name collisions.
Reserve ALL UPPERCASE names for macros, to reduce the chance of name collisions and inadvertent text substitution.
Preferentially pass potentially "large" objects, such as std::string, by reference, e.g. formal argument type std::string const&, in order to avoid excessive copying. There are some exceptions to this rule when one aims for perfect code, e.g. for C++11 move semantics, but it's a good general rule.
employees[i] is of type Employee. So either you have to print like
cout<<employees[i].getName(); // so on
Or you have to overload << operator for Employee type:
ostream& operator<<(ostream& stream, Employee const& emp );
Firstly. in my machine it compiles fine
Secondly, you are doing:
string name = nm;
So name is a automatic variable, Not the member of your class. You should do like:
name = nm; // if you delete int name; line
Or,
this->name = nm;
Some changes of your code:
Employee::Employee()
: yearsWorked( 0 )
{
}
Employee::Employee(string nm, string id)
: name( nm ), idNumber( id ), yearsWorked( 0 )
{
}
Employee::Employee(string nm, string id)
: name( nm ), idNumber( id ), department( dpt ), position( pos ), yearsWorked( years ),
{
}
std::ostream & operator <<( std::ostream &os, const Employee &emp )
{
return ( os << "ID: " << emp.idNumber << ", name: " << emp.name
<< ", department: " << emp.department << ", position: " << emp.position
<< ", years worked: " << emp.yearsWorked );
}