0

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();
}
7
  • 1
    is there any special reason that you do not want std::vector<Person> personArray? Commented Sep 5, 2018 at 16:38
  • I am being tasked with using an array specifically. Vector is generally preferred because the size being dynamically adjusted, correct? Commented Sep 5, 2018 at 16:56
  • Yes. But here the size seems to be fixed. Then you can use std::vector::reserve to reserve the size of your array(probably in the constructor of Roster) and no re allocation will occur. Or simply use std::array with a fixed size. Commented Sep 5, 2018 at 16:59
  • @MarkScheer First, there is no "Person" array anywhere in your code. You have an array of pointers to Persons. If you really did have a Person array, then it is a simple matter of creating a Person and assigning it to one of the array elements, no different than if you had an int array and want to assing an int to one of the array entries. Commented Sep 5, 2018 at 17:00
  • Vector is generally preferred because the size being dynamically adjusted, correct? -- Your printPersonArray accesses uninitialized pointers, since your loop just assumes there are 5 valid entries. If there is any reason for vector, that alone is one of them, regardless if vector is dynamic or not. Commented Sep 5, 2018 at 17:13

2 Answers 2

2

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
Sign up to request clarification or add additional context in comments.

Comments

2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.