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.
Related
I am trying to call printTotals() from main(). I tried person.printTotals() but it does not work because agent only calls functions within the vector STL. I checked other answers, such as C++ Calling Vectors from Function to Main and Using vector of user defined class type objects and How to create a vector of class objects in C++?.
I also checked my STL book, but this case it is not in there.
I have two questions:
Is there a way to call printTotals() outside of the constructor? Can I call it from main()? I want to keep my code clean and modular, but I am unable to access it outside of the constructor.
Each person has 3 neighbors consisting of Persons in a vector. I thought about declaring the neighbors vector like this, but was not sure:
vector<Person> neighbor
For a specific person with id = 3, how can I retrieve their second neighbor's voting status? Would it be:
person[3].neighbor[1].getPersonVotingStatus()?
This is my code:
Person.h
#include <iostream>
#include <string.h>
#include <vector>
class Person
{
public:
Person();
Person( std::vector<Person> person, maxPersons);
std::string getPersonVotingStatus(int ID);
void printTotals();
private:
std::string personName;
float personHeight;
int personID;
std::string isVoter;
vector<Person>neighbor; // <---
}
Person.cpp
#include <iostream>
#include <string.h>
#include <vector>
Person::Person()
{}
Person::Person(int pID, float pHeight, std::string pName, std::string isV)
{
personID = pID;
personHeight = pHeight;
personName = pName;
isVoter = isV;
}
Person::Person( std::vector<Person> person, int maxPersons)
{
for(int = 0; i < maxPersons; i++)
{
person[i].personID = i;
person[i].personHeight = i + 100;
person[i].personName = "testName";
if (i / 2 = 0) {
person[i].isVoter = "yes";
}
else {
person[i].isVoter = "no";
}
}
Person(person[i].personID, person[i].personHeight, person[i].personName, person[i].isVoter);
}
std::String getPersonVotingStatus( int ID)
{
return person[i].isVoter;
}
void printTotals( std::vector<Person> person)
{
int totalVoter = 0;
int totalNonvoter = 0;
for (int i = 0; i< person.size(); i++)
if (person[i].isVoter == "yes") {
totalVoter++;
}
else {
totalNonvoter++;
}
}
main.cpp
#include <iostream>
#include <string.h>
#include <vector>
int main()
{
int maxPersons = 10;
std::vector<Person> person;
Person obj( person, maxPersons);
person.printTotals(); // <--
return 0;
}
Try defining printTotals() as a static function:
class Person
{
public:
static void printTotals(std::vector<Person> person);
}
Then you can call it in main like this:
Person::printTotals(person);
I'm new to C++ classes, objects and especially overcharging operators.
Given the following main function, I have to work around it, so that in the end, the program will compile and run correctly. Here is the main function:
int main()
{
TOperator *oper = new TOperator("Alexandru");
TComanda *command = new TComanda("online", oper);
command += new Item("usb stick", 220); // this is calling Item's constructor
command += new Item("tastatura", 175);
oper->afiseazaCommanda();// printing out the final cart
return 0;
}
The main problems I'm facing so far are:
1)How can I overload the += operator, so that I could add up the strings ( same as in python when doin + for two strings ) and also sum up my two integers?
2)How should I write my afiseazaComanda() function from TOperator, so that It will work out properly? Because, so far, when trying to compile it, it is giving me an error that "Item was not declared in this scope".
I've tried to get some information about global operator overloading but didn't find much.
Searching through SO didn't really help, because it wasn't talking about overcharging the operator in such way, so that the object of class TComanda could overcharge the class Item, so I hope that I could find some clear help there.
Here is the code for my classes:
class Item
{
public:
string Product;
int Price;
Item(string product, int price)
{
Product = product;
Price = price;
}
friend class TComanda;
};
class TOperator
{
string Name;
public:
TOperator(string n)
{
Name = n;
}
void afiseazaComanda()
{
cout << Item.Product << " " << Item.Price; // supposed to print out the final cart with both the products and summed prices
}
friend class TComanda;
};
class TComanda
{
string online, name;
public:
TComanda(string onoroff, TOperator *op)
{
online = onoroff;
this->name = op->Name;
}
TComanda operator +=(Item &a)
{
a+=a.Product;
a+=a.Price;
return *this;
} // still thinking how I could write that part of the code
};
You can't implement custom operators for pointers, only objects. So, for instance, since you declared command as a TComanda* pointer, you would have to dereference command to access the TComanda object it is pointing at, eg:
*command += new Item("usb stick", 220);
Except that you have TComanda:::operator+= declared to take an Item& reference, not an Item* pointer, so you would have to dereference the Item* pointer, too:
*command += *(new Item("usb stick", 220));
Which is a memory leak, since you are losing access to the Item object you new'ed, so you can't delete it when you are done using it (in fact, your whole main() is leaking every object it new's). So, get rid of the new here:
*command += Item("usb stick", 220);
In which case, you may as well get rid of new on command and oper, too:
TOperator oper("Alexandru");
TComanda command("online", &oper);
command += Item("usb stick", 220);
command += Item("tastatura", 175);
That being said, your whole code design is incomplete for what you are attempting, as TOperator has no concept of TComanda, but even if it did, TComanda does not store its added Items anywhere that TOperator can reach them.
Try this:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Item
{
public:
string Product;
int Price;
Item(const string &product, int price);
};
class TComanda;
class TOperator
{
string Name;
TComanda *Command = nullptr;
public:
TOperator(const string &name);
void afiseazaCommanda() const;
friend class TComanda;
};
class TComanda
{
string Online, Name;
vector<Item> Items;
TOperator &Operator;
public:
TComanda(const string &onoroff, TOperator &op);
~TComanda();
TComanda& operator +=(const Item &a);
friend class TOperator;
};
Item::Item(const string &product, int price)
{
Product = product;
Price = price;
}
TOperator::TOperator(const string &name)
{
Name = name;
}
void TOperator::afiseazaCommanda() const
{
if (Command) {
for(const auto &item : Command->Items) {
cout << item.Product << " " << item.Price << endl;
}
}
}
TComanda::TComanda(const string &onoroff, TOperator &op)
: Operator(op)
{
Online = onoroff;
Name = Operator.Name;
Operator.Command = this;
}
TComanda::~TComanda()
{
if (Operator.Command == this)
Operator.Command = nullptr;
}
TComanda& TComanda::operator +=(const Item &a)
{
Items.push_back(a);
return *this;
}
int main()
{
TOperator oper("Alexandru");
TComanda command("online", oper);
command += Item("usb stick", 220);
command += Item("tastatura", 175);
oper.afiseazaCommanda();
return 0;
}
Online Demo
UPDATE:
Given the restriction you have on the code in main(), try something like this instead:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Item
{
public:
string Product;
int Price;
Item(const string &product, int price);
};
class TComanda;
class TOperator
{
string Name;
TComanda *Command = nullptr;
public:
TOperator(const string &name);
void afiseazaCommanda() const;
friend class TComanda;
};
class TComanda
{
string Online, Name;
vector<Item*> Items;
TOperator *Operator;
public:
TComanda(const string &onoroff, TOperator *op);
~TComanda();
TComanda& operator +=(Item *a);
friend class TOperator;
};
Item::Item(const string &product, int price)
{
Product = product;
Price = price;
}
TOperator::TOperator(const string &name)
{
Name = name;
}
void TOperator::afiseazaCommanda() const
{
if (Command) {
for(const auto *item : Command->Items) {
cout << item->Product << " " << item->Price << endl;
}
}
}
TComanda::TComanda(const string &onoroff, TOperator *op)
{
Online = onoroff;
Operator = op;
Name = Operator->Name;
Operator->Command = this;
}
TComanda::~TComanda()
{
for(auto *item : Items)
delete item;
if (Operator->Command == this)
Operator->Command = nullptr;
}
TComanda& TComanda::operator +=(Item *a)
{
Items.push_back(a);
return *this;
}
int main()
{
TOperator *oper = new TOperator("Alexandru");
TComanda *command = new TComanda("online", oper);
*command += new Item("usb stick", 220);
*command += new Item("tastatura", 175);
oper->afiseazaCommanda();
delete command;
delete oper;
return 0;
}
Online Demo
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;
}
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.
The subject (I mean overloading operators, default and copy constructors etc.) is something new for me and I really don't get it. I tried to avoid it but it has got me anyway. I have a container std::vector<Employee> with objects. Even thought I don't use = operator
I get the error:
C2280 'Employee &Employee::operator =(const Employee &)': attempting to reference a deleted function.
The error stops occur if I remove the line employees.erase(employees.begin() + 1);
I've found out that is a common problem but still I can't find any solution. Please take a look at the code:
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
class Employee
{
public:
std::string name, profession;
std::string current_task = "NONE";
int id, age, warrings;
std::vector<std::string>& tasks;
Employee::Employee(std::vector<std::string>& tasks) : tasks(tasks)
{
warrings = 0;
};
virtual void AssignNewTask(std::string input_string)
{
for (unsigned int i = 0; i < tasks.size(); i++)
{
if (input_string == tasks[i])
{
current_task = input_string;
std::cout << ">> Przydzielony nowy task!" << std::endl;
return;
}
}
std::cout << input_string << "nie nalezy do listy obowiazkow " << profession << std::endl;
}
};
class HR : public Employee
{
private:
static std::vector<std::string> tasks;
public:
HR::HR() : Employee(tasks)
{
Employee::profession = "HR Specialist";
}
};
class Helpdesk : public Employee
{
private:
static std::vector<std::string> tasks;
public:
Helpdesk::Helpdesk() : Employee(tasks)
{
Employee::profession = "Helpdesk Technician";
}
};
std::vector<std::string> HR::tasks = { "HR task" };
std::vector<std::string> Helpdesk::tasks = { "Helpdesk task" };
bool operator==(const Employee & obj, const std::string & std)
{
if ((obj.name == std) || (std == obj.name))
{
return true;
}
else
{
return false;
}
}
int main()
{
std::vector<Employee> employees;
std::cout << "Welcome message" << std::endl;
// it works
employees.push_back(HR());
employees.push_back(Helpdesk());
// it also works
employees.pop_back();
employees.push_back(Helpdesk());
// the issue occurs !
employees.erase(employees.begin() + 1);
system("pause");
}
I guess that I should overload a = operator but I even don't know how to begin. I've marked where the issue occurs.
The problem is here:
class Employee
{
public:
std::string name, profession;
std::string current_task = "NONE";
int id, age, warrings;
std::vector<std::string> *tasks; // <=== use a pointer
Employee(std::vector<std::string>& tasks) : tasks(&tasks)
{
warrings = 0;
};
You can't define a operator= since you can't assign a reference (tasks). Remove the reference and it will be all OK (maybe slower, but safer)