Link to home
Start Free TrialLog in
Avatar of rijku
rijku

asked on

C++ - Conversion from static to dynamic arrays + pointers.

Hi!
Im extending a old program I've made. Im changing all the static arrays into dynamic arrays and using pointers aswell.

Program
The program is a transaction jar which functions as if three people are out on a dinner then one of the three may pay for all of them, and then someone else pays for the next time's activity, so if the dinner costs 120, then person B and C are in a 40 debt each to person A.
____________________________________________________________________________

I thought that I just should change the first (Transaction) class first and make the program work with that, and then change the rest of the program. I tried add a copy-, and a assignment constructor and a destructor. However I just got runtime errors so I feel pretty lost where I´ve failed.
I'd gladly accept some input.

TransactionJar_Dyn.cpp is the file im using with infile "pot.txt", and the program im using is Code::Blocks 10.05
T-Jar.cpp
pot.txt
TransactionJar-Dyn.cpp
ASKER CERTIFIED SOLUTION
Avatar of Infinity08
Infinity08
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Why don't you just change your code to use a vector?
http://www.cplusplus.com/reference/stl/vector/

That's going to be far simpler (and safer) that doing lots of dynamic allocations all over the place and for the most part you should be able to work with a vector without changing much existing code since a vector is designed to have almost the same syntax and semantics as a normal C style array.
Avatar of rijku
rijku

ASKER

@evilrix  
Im supposed not to use vectors.

@Infinity08
I first get to the menu in my main where I can choose a number between 0-6. When I've entered a number, MS windows "the program have stopped working" window pops up and then in the application window i get
Process returned -1073741819 (0xC0000005)  or
Process returned 255 (OxFF)
depending on if I cancel respectively wait for the MS window to be done.
>> When I've entered a number

What number would that be ? Did you do anything else before entering that number ? Can you post the complete output of your code ?

Btw, I notice that you've never initialized the choice variable, so depending on the conditions, it might have the value 0, which would cause the while loop to be skipped entirely.
>> Im supposed not to use vectors.

Hmmm, your comment "Im extending a old program I've made" would imply there are no restrictions on how you do this but that statement would imply this is possibly an assignment. Please clarify so that the experts can gauge their responses accordingly.

https://www.experts-exchange.com/help.jsp?hi=21

Other than that I'm going to leave you in Infinity08 expert hands as too many experts just make life confusing :)
Avatar of rijku

ASKER

@evilrix yeah sorry about that. yes it's an assignment so I dont want anyone to make a program for me but i would appreciate guidance or something like it.

@Infinity08 After I run the application, the first thing i do is enter a number, the menu shows itself automatically before that. I tried to input different (ranging from 0-6) numbers and the result is
Process returned -1073741819 (0xC0000005) or Process returned 255 (OxFF)
for every input as the screencast shows. Not just for 2 but for all numbers. I haven't seen why it returns differently from time to time.
I tried to initialize "choice" with negative and positive numbers but I didn't see any difference in doing so. However should I keep "choice" initialized? Is it preferable?

The methods I added in "TransactionJar_Dyn.cpp" is the copy constructor, assignment constructor and changed the destructor in the transaction class. All apart that is that i've changed the string friends[MAX_FRIENDS]; into string *friends; in the transaction class.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;

const int MAX_PERSONS = 10;
const int MAX_TRANSACTIONS = 30;
const int MAX_FRIENDS = 10;

class Transaction
{
    private:
    string date;
    string type;
    string name;
    double amount;
    int num_friends;
    string *friends; // OLD: string friends[MAX_FRIENDS];

    public:
    Transaction();

    Transaction(int nSize,int v);

    ~Transaction();

    Transaction(const Transaction &t);

    string get_name();
    double get_amount();
    int get_num_friends();
    bool existFriend(string theeName);
    bool readATrans(istream &is);
    void writeATrans(ostream &os);
};

class Person
{
    private:
    string name;
    double paid_others;
    double debt;

    public:
    Person();
    Person(string n, double b, double s);
    double get_paid();
    double get_debt();
    void printOut_P();
};

class PersonList
{
    private:
    int num_persons;
    Person pers[MAX_PERSONS];

    public:
    PersonList();
    ~PersonList();
    void addAnotherP(Person pny);
    void printOutAndFix();
    double sumDebt();
    double sumPaid();
};

class TransactionsList
{
    private:
    Transaction trans[MAX_TRANSACTIONS];
    int numTrans;

    public:
    TransactionsList();
    ~TransactionsList();
    void loadin(istream &is);
    void printout_TL(ostream &os);
    void addMore_TL(Transaction &t);
    double totalcost();
    double havePaid(string theeName);
    double theDebt(string theeName);
    PersonList FixPersons();

    int showAddMore_TL();
};

/* ------------------- *
 * --- TRANSACTION --- *
 * ------------------- */
Transaction::Transaction()
:date(), type(), name(), amount(), num_friends(), friends()
{
}

Transaction::Transaction(int nSize, int v)
:date(), type(), name(), amount(), num_friends(), friends()
{
    if (num_friends > 0)
    {
        friends = new string[num_friends];
        for (int i = 0; i < num_friends; i++)
            friends[i] = v;
    }

    else
    {
        friends = 0;
    }
}

Transaction::Transaction(const Transaction &t)
:date(), type(), name(), amount(), num_friends(), friends()
{
    if (num_friends > 0)
    {
        friends = new string[num_friends];
        for (int i = 0; i < num_friends; i++)
            friends[i] = t.friends[i];
    }

    else
    friends = 0;
}

Transaction::~Transaction()
{
    delete [] friends;
}

string Transaction::get_name()
{
    return name;
}

double Transaction::get_amount()
{
    return amount;
}

int Transaction::get_num_friends()
{
    return num_friends;
}

bool Transaction::existFriend(string theeName)
{
    for (int i = 0; i < num_friends; i++)
    {
        if (theeName == friends[i])
        {
            return true;
        }
    }
    return false;
}

bool Transaction::readATrans(istream &is)
{
    is >> date >> type >> name >> amount >> num_friends;

    for (int i = 0; i < num_friends; i++)
    {
        is >> friends[i];
    }

    return is;
}

void Transaction::writeATrans(ostream &os)
{
    os << date << "\t" << type << "\t" << name << "\t" << amount << "\t" << num_friends << "\t";

    for (int i = 0; i < num_friends; i++)
    {
        os << friends[i] << " ";
    }

    os << endl;
}

/* ------------------------ *
 * --- TRANSACTIONSLIST --- *
 * ------------------------ */

TransactionsList::TransactionsList()
:numTrans()
{
    numTrans = 0;
}

TransactionsList::~TransactionsList()
{
}

void TransactionsList::loadin(istream &is)
{
    Transaction t;

    while (t.readATrans(is))
    {
        addMore_TL(t);
    }
}

void TransactionsList::printout_TL(ostream &os)
{
    for (int i = 0; i < numTrans; i++)
    {
        trans[i].writeATrans(os);
    }
}

void TransactionsList::addMore_TL(Transaction &t)
{
    trans[numTrans] = t;
    numTrans++;
}

int TransactionsList::showAddMore_TL()
{
    return numTrans;
}

double TransactionsList::totalcost()
{
    double expense = 0.0;

    for (int i = 0; i < numTrans; i++)
    {
        expense += trans[i].get_amount();
    }

    return expense;
}

double TransactionsList::havePaid(string theeName)
{
    double paid = 0.0;

    for (int i = 0; i < numTrans; i++)
    {
        if (theeName == trans[i].get_name())
        {
            paid += (trans[i].get_amount()) - ((trans[i].get_amount()) / (trans[i].get_num_friends()+1)); // /(trans[i].get_num_friends()+1);
        }
    }

    return paid;
}

double TransactionsList::theDebt(string theeName)
{
    double debt = 0.0;

    for (int i = 0; i < numTrans; i++)
    {
        if (trans[i].existFriend(theeName))
        {
            debt += (trans[i].get_amount())/(trans[i].get_num_friends()+1);
        }
    }

    return debt;
}

PersonList TransactionsList::FixPersons()
{
    PersonList pl = PersonList();
    string s_arr[MAX_PERSONS];
    int num_pers = 0;
    string name = "";

    for (int i = 0; i < numTrans; i++)
    {
        Transaction t = trans[i];

        name = t.get_name();
        bool nameExist = false;

        for ( int k = 0; k < num_pers; k++)
        {
            if (s_arr[k] == name)
            {
                nameExist = true;
            }
        }

        if(!nameExist)
        {
            s_arr[num_pers] = name;
            num_pers++;
        }
    }

    for(int i = 0; i < num_pers; i++)
    {
        name = s_arr[i];
        Person p = Person(name, havePaid(name), theDebt(name));
        pl.addAnotherP(p);
    }

    return pl;
}

/* -------------- *
 * --- PERSON --- *
 * -------------- */

Person::Person ()
:name(), paid_others(), debt()
{
}

Person::Person (string n, double b, double s)
:name(), paid_others(), debt()
{
    name = n;
    paid_others = b;
    debt = s;
}

double Person::get_paid()
{
    return paid_others;
}

double Person::get_debt()
{
    return debt;
}

void Person::printOut_P()
{
    cout << name << "\tPaid others: " << paid_others << "\tdebt: " << debt << endl;

    if (debt > paid_others)
    {
        cout << "Pot takes " << debt - paid_others << endl;
    }

    if (debt < paid_others)
    {
        cout << "Pot gives " << paid_others - debt << endl;
    }

    if (debt == paid_others)
    {
        cout << "Pot is happy! " << endl;
    }
}

/* ------------------ *
 * --- PERSONLIST --- *
 * ------------------ */

PersonList::PersonList()
:num_persons()
{
    num_persons = 0;
}

PersonList::~PersonList()
{
}

void PersonList::addAnotherP(Person pny)
{
    pers[num_persons] = pny;
    num_persons++;
}

void PersonList::printOutAndFix()
{
    for (int i = 0; i < num_persons; i++)
    {
        pers[i].printOut_P();
    }
}

double PersonList::sumDebt()
{
    double sd = 0.0;

    for ( int i = 0; i < num_persons; i++)
    {
        sd += pers[i].get_debt();
    }

    return sd;
}

double PersonList::sumPaid()
{
    double sp = 0.0;

    for ( int i = 0; i < num_persons; i++)
    {
        sp += pers[i].get_paid();
    }

    return sp;
}

/* ------------ *
 * --- MAIN --- *
 * ------------ */

int main()
{
    Transaction t;
    TransactionsList tl;
    Person p;
    PersonList pl;

    int choice = -1;
    string theeName;

    ifstream is("pot.txt");
    ofstream os("rewrite.txt");

    while (choice != 0)
    {
        cout << "What do you wanna do? Make your choice in the menu" << endl;
        cout << "0. Exit. All transactions will be saved to a file. " << endl;
        cout << "1. Write a transaction from the keyboard " << endl;
        cout << "2. Print out information from all transactions " << endl;
        cout << "3. Calculate the total cost. " << endl;
        cout << "4. How much is a specified person's debt? " << endl;
        cout << "5. How much have a person paid for others? " << endl;
        cout << "6. List all persons and fix. " << endl;
        cin >> choice;
        cout << endl;

        tl.loadin(is);

        switch(choice)
        {
            case 0:
            {
                tl.printout_TL(os);
                break;
            }

            case 1:
            {
                cout << "Please insert with space between " << endl << "[YYMMDD, type, name, numOfFriends, nameOffriends] " << endl;
                t.readATrans(cin);
                tl.addMore_TL(t);
                break;
            }

            case 2:
            {
                cout << "Num. of trans. = " << tl.showAddMore_TL() << endl;
                tl.printout_TL(cout);
                cout << endl;
                break;
            }

            case 3:
            {
                cout << "The total expenses are " << tl.totalcost() << endl << endl;
                break;
            }

            case 4:
            {
                cout << "Specify a name: " << endl;
                cin >> theeName;
                cout << theeName << "'s debt is " << tl.theDebt(theeName) << endl << endl;
                break;
            }

            case 5:
            {
                cout << "Specify a name: " << endl;
                cin >> theeName;
                cout << theeName << " has paid " << tl.havePaid(theeName) << endl << endl;
                break;
            }

            case 6:
            {
                pl = tl.FixPersons();
                pl.printOutAndFix();
                cout << endl;
                break;
            }

            default:
            {
                cout << "Please try again (0-6) " << endl;
            }
        }
    }

    return 0;
}

Open in new window

rijku-457114.flv
>> I tried to input different (ranging from 0-6) numbers and the result is
Process returned -1073741819 (0xC0000005) or Process returned 255 (OxFF)

In your Transaction class, you have this data member :

>>     string *friends; // OLD: string friends[MAX_FRIENDS];

but you don't allocate memory for this pointer before you call the readATrans method. And this method tries to access the memory that the pointer points to :

>>         is >> friends[ i ];

but since you haven't allocated memory for it yet, it fails.

You need to make sure that you allocate enough memory for the friends array, before you try to use it.



>> However should I keep "choice" initialized? Is it preferable?

Yes, it's a good habit to initialize your variables, since uninitialized variables can have any contents. And this often leads to unexpected behavior.
Avatar of rijku

ASKER

I see, but shouldn't it allocate memory in Transaction::Transaction(const Transaction &t) with
friends = new string[num_friends];    ?
Or should I add a method in style with "void Transaction::assign(const Transaction &t) which includes delete[], new[], and a for-loop to copy all the elements regarding the friends array? Otherwise, I am not sure of how to allocate sufficient memory.
>> I see, but shouldn't it allocate memory in Transaction::Transaction(const Transaction &t) with

That's the copy constructor. But you're not using the copy constructor to construct the Transaction object. You're using the default constructor :

>>     Transaction t;

(in the TransactionsList::loadin method)
Avatar of rijku

ASKER

So I must change Transaction t; so it uses the copy constructor instead of the default-? I tried to figure it out with the help of http://en.wikipedia.org/wiki/Copy_constructor. But I didn't really get clear how to define it. To me, it would be something like this:
Transaction t = Transaction(); or like Transaction t; Transaction t2; t2 = t;
But It feels like there are some more to it.
>> So I must change Transaction t; so it uses the copy constructor instead of the default-?

A copy constructor makes a copy of an existing object. Do you have an existing Transaction object to copy ?

Do you know how many items you'll put in the friends array ? Is there a maximum ? Do you either have a constructor that constructs a Transaction object from scratch, and makes sure to have enough room for the necessary amount of friends . Or can you alternatively make sure to do the necessary allocation otherwise ?
Avatar of rijku

ASKER

Hmm, well I got a file as ifstream which are being used in the loadin method?

I have no restrictions of minimum nor maximum values in the application.
I am a bit of unsure of this constructors still that you´re talking about. But what I believed and would prefer is that the constructor is in charge for all of the necessary allocation and I guess that's what I atleast have tried with.
Then make sure that you let the constructor allocate the appropriate amount of memory.

Right now, you have 3 constructors :

1) the default constructor that allocates no memory
2) a constructor that takes a size as parameter, but doesn't use it (it was probably intended to allocate the given amount of memory)
3) a copy constructor
Avatar of rijku

ASKER

I have been thinking about how to use the parameters in the assignment constructor, I've tried to declare the size parameter in the initialization list, but, I don't know where to go from there, like how I should do to allocate sufficient memory with the parameter size and get it to a sufficient size.
>> I've tried to declare the size parameter in the initialization list,

In the initialization list, you have this :

>> num_friends()

If you want to set num_friends to the nSize value passed as parameter to the constructor, you should use :

        num_friends(nSize)

instead.
Avatar of rijku

ASKER

Oh, sorry I missed linking code, anyway, I mean I've done what you described just now.
And don't know what I should be doing next, If there's something missing in relation to the constructors? Because the error is still here.
Well, once you have initialized the member variables correctly, can you then ensure that enough memory is allocated for the friends array ?
Avatar of rijku

ASKER

Well, I feel unsure about this, but,  in the assignment operator I thought that I changed the size of the array to nSize and then allocated sufficient memory and then changed all elements to v.
And no, I can't ensure that while I feel unsure about this stuff still.
Avatar of rijku

ASKER

Now I've changed and added "0" to friends in the member initialization list in the default constructor, and I added: delete [] kompisar; kompisar = new string[ant_kompisar]; to the readATrans function.
I've also added a function for the "deep copy", and used it in the loadin function.
void Transaction::assign(const Transaction &t)
{
    // assign: actual object = t.

    num_friends = t.num_friends;

    if (num_friends > 0)
    {
        delete [] friends; // Release memory.
        friends = new string[ant_num_friends]; // Allocate new memory.

        for (int i = 0; i < num_friends; i++)
        {
            friends[i] = t.friends[i]; // Copy elements.
        }
    }
    else
    friends = 0; // NULL.
}

Open in new window

>> No answer in quite some days now, and have come long way with new code

You didn't ask a question in quite some days, so I assumed you were just working on things.

In any case, the original question was about the crash that you experienced, and the reason for that was pointed out. If you haven't been able to resolve it with the advice given here, I'd be happy to assist you further.
Avatar of rijku

ASKER

Sorry If I was unclear! However I've been working on stuff, and added a new method called assign, which should work as "deep copy".

However I still get this error 0xC0000005 - access violation, and I don't really understand how I could prevent it, how I should change my code so it doesn't do that.

New code:


#include <fstream>
#include <iostream>
#include <string>
using namespace std;

const int MAX_PERSONS = 10;
const int MAX_TRANSACTIONS = 30;
const int MAX_FRIENDS = 10;

class Transaction
{
    private:
    string date;
    string type;
    string name;
    double amount;
    int num_friends;
    string *friends; // OLD: string friends[MAX_FRIENDS];

    public:
    Transaction();

    Transaction(int nSize,int v);

    ~Transaction();

    Transaction(const Transaction &t);

    void assign(const Transaction &t);

    string get_name();
    double get_amount();
    int get_num_friends();
    bool existFriend(string theeName);
    bool readATrans(istream &is);
    void writeATrans(ostream &os);
};

class Person
{
    private:
    string name;
    double paid_others;
    double debt;

    public:
    Person();
    Person(string n, double b, double s);
    double get_paid();
    double get_debt();
    void printOut_P();
};

class PersonList
{
    private:
    int num_persons;
    Person pers[MAX_PERSONS];

    public:
    PersonList();
    ~PersonList();
    void addAnotherP(Person pny);
    void printOutAndFix();
    double sumDebt();
    double sumPaid();
};

class TransactionsList
{
    private:
    Transaction trans[MAX_TRANSACTIONS];
    int numTrans;

    public:
    TransactionsList();
    ~TransactionsList();
    void loadin(istream &is);
    void printout_TL(ostream &os);
    void addMore_TL(Transaction &t);
    double totalcost();
    double havePaid(string theeName);
    double theDebt(string theeName);
    PersonList FixPersons();

    int showAddMore_TL();
};

/* ------------------- *
 * --- TRANSACTION --- *
 * ------------------- */
Transaction::Transaction()
:date(), type(), name(), amount(), num_friends(), friends(0)
{
}

Transaction::Transaction(int nSize, int v)
:date(), type(), name(), amount(), num_friends(nSize), friends()
{
    if (num_friends > 0)
    {
        friends = new string[num_friends]; // allocate memory.
        for (int i = 0; i < num_friends; i++)
            friends[i] = v;
    }

    else
    {
        friends = 0; // NULL-pointer.
    }
}

Transaction::Transaction(const Transaction &t)
:date(t.date), type(t.type), name(t.name), amount(t.amount), num_friends(t.num_friends), friends(t.friends)
{
    if (num_friends > 0)
    {
        friends = new string[num_friends]; // allocate new memory.
        for (int i = 0; i < num_friends; i++)
            friends[i] = t.friends[i]; // copy the elements.
    }

    else
    friends = 0; // NULL.
}

Transaction::~Transaction()
{
    delete [] friends;
}

string Transaction::get_name()
{
    return name;
}

double Transaction::get_amount()
{
    return amount;
}

int Transaction::get_num_friends()
{
    return num_friends;
}

bool Transaction::existFriend(string theeName)
{
    for (int i = 0; i < num_friends; i++)
    {
        if (theeName == friends[i])
        {
            return true;
        }
    }
    return false;
}

bool Transaction::readATrans(istream &is)
{
    delete [] friends;
    friends = new string[num_friends];

    is >> date >> type >> name >> amount >> num_friends;

    for (int i = 0; i < num_friends; i++)
    {
        is >> friends[i];
    }

    return is;
}

void Transaction::writeATrans(ostream &os)
{
    os << date << "\t" << type << "\t" << name << "\t" << amount << "\t" << num_friends << "\t";

    for (int i = 0; i < num_friends; i++)
    {
        os << friends[i] << " ";
    }

    os << endl;
}

void Transaction::assign(const Transaction &t)
{
    // Assign: actual object = t.

    num_friends = t.num_friends;

    if (num_friends > 0)
    {
        delete [] friends; // release memory.
        friends = new string[num_friends]; // Allocate memory.

        for (int i = 0; i < num_friends; i++)
        {
            friends[i] = t.friends[i]; // Copy elements.
        }
    }
    else
    friends = 0; // NULL.
}

/* ------------------------ *
 * --- TRANSACTIONSLIST --- *
 * ------------------------ */

TransactionsList::TransactionsList()
:numTrans()
{
    numTrans = 0;
}

TransactionsList::~TransactionsList()
{
}

void TransactionsList::loadin(istream &is)
{
    Transaction t;

    while (t.readATrans(is))
    {
        addMore_TL(t);
    }
}

void TransactionsList::printout_TL(ostream &os)
{
    for (int i = 0; i < numTrans; i++)
    {
        trans[i].writeATrans(os);
    }
}

void TransactionsList::addMore_TL(Transaction &t)
{
    trans[numTrans].assign(t); //trans[numTrans] = t;
    numTrans++;
}

int TransactionsList::showAddMore_TL()
{
    return numTrans;
}

double TransactionsList::totalcost()
{
    double expense = 0.0;

    for (int i = 0; i < numTrans; i++)
    {
        expense += trans[i].get_amount();
    }

    return expense;
}

double TransactionsList::havePaid(string theeName)
{
    double paid = 0.0;

    for (int i = 0; i < numTrans; i++)
    {
        if (theeName == trans[i].get_name())
        {
            paid += (trans[i].get_amount()) - ((trans[i].get_amount()) / (trans[i].get_num_friends()+1)); // /(trans[i].get_num_friends()+1);
        }
    }

    return paid;
}

double TransactionsList::theDebt(string theeName)
{
    double debt = 0.0;

    for (int i = 0; i < numTrans; i++)
    {
        if (trans[i].existFriend(theeName))
        {
            debt += (trans[i].get_amount())/(trans[i].get_num_friends()+1);
        }
    }

    return debt;
}

PersonList TransactionsList::FixPersons()
{
    PersonList pl = PersonList();
    string s_arr[MAX_PERSONS];
    int num_pers = 0;
    string name = "";

    for (int i = 0; i < numTrans; i++)
    {
        Transaction t;
        trans[i].assign(t); // t = trans[i];

        name = t.get_name();
        bool nameExist = false;

        for ( int k = 0; k < num_pers; k++)
        {
            if (s_arr[k] == name)
            {
                nameExist = true;
            }
        }

        if(!nameExist)
        {
            s_arr[num_pers] = name;
            num_pers++;
        }
    }

    for(int i = 0; i < num_pers; i++)
    {
        name = s_arr[i];
        Person p = Person(name, havePaid(name), theDebt(name));
        pl.addAnotherP(p);
    }

    return pl;
}

/* -------------- *
 * --- PERSON --- *
 * -------------- */

Person::Person ()
:name(), paid_others(), debt()
{
}

Person::Person (string n, double b, double s)
:name(), paid_others(), debt()
{
    name = n;
    paid_others = b;
    debt = s;
}

double Person::get_paid()
{
    return paid_others;
}

double Person::get_debt()
{
    return debt;
}

void Person::printOut_P()
{
    cout << name << "\tPaid others: " << paid_others << "\tdebt: " << debt << endl;

    if (debt > paid_others)
    {
        cout << "Pot takes " << debt - paid_others << endl;
    }

    if (debt < paid_others)
    {
        cout << "Pot gives " << paid_others - debt << endl;
    }

    if (debt == paid_others)
    {
        cout << "Pot is happy! " << endl;
    }
}

/* ------------------ *
 * --- PERSONLIST --- *
 * ------------------ */

PersonList::PersonList()
:num_persons()
{
    num_persons = 0;
}

PersonList::~PersonList()
{
}

void PersonList::addAnotherP(Person pny)
{
    pers[num_persons] = pny;
    num_persons++;
}

void PersonList::printOutAndFix()
{
    for (int i = 0; i < num_persons; i++)
    {
        pers[i].printOut_P();
    }
}

double PersonList::sumDebt()
{
    double sd = 0.0;

    for ( int i = 0; i < num_persons; i++)
    {
        sd += pers[i].get_debt();
    }

    return sd;
}

double PersonList::sumPaid()
{
    double sp = 0.0;

    for ( int i = 0; i < num_persons; i++)
    {
        sp += pers[i].get_paid();
    }

    return sp;
}

/* ------------ *
 * --- MAIN --- *
 * ------------ */

int main()
{
    Transaction t;
    TransactionsList tl;
    Person p;
    PersonList pl;

    int choice = -1;
    string theeName;

    ifstream is("pot.txt");
    ofstream os("rewrite.txt");

    while (choice != 0)
    {
        cout << "What do you wanna do? Make your choice in the menu" << endl;
        cout << "0. Exit. All transactions will be saved to a file. " << endl;
        cout << "1. Write a transaction from the keyboard " << endl;
        cout << "2. Print out information from all transactions " << endl;
        cout << "3. Calculate the total cost. " << endl;
        cout << "4. How much is a specified person's debt? " << endl;
        cout << "5. How much have a person paid for others? " << endl;
        cout << "6. List all persons and fix. " << endl;
        cin >> choice;
        cout << endl;

        tl.loadin(is);

        switch(choice)
        {
            case 0:
            {
                tl.printout_TL(os);
                break;
            }

            case 1:
            {
                cout << "Please insert with space between " << endl << "[YYMMDD, type, name, numOfFriends, nameOffriends] " << endl;
                t.readATrans(cin);
                tl.addMore_TL(t);
                break;
            }

            case 2:
            {
                cout << "Num. of trans. = " << tl.showAddMore_TL() << endl;
                tl.printout_TL(cout);
                cout << endl;
                break;
            }

            case 3:
            {
                cout << "The total expenses are " << tl.totalcost() << endl << endl;
                break;
            }

            case 4:
            {
                cout << "Specify a name: " << endl;
                cin >> theeName;
                cout << theeName << "'s debt is " << tl.theDebt(theeName) << endl << endl;
                break;
            }

            case 5:
            {
                cout << "Specify a name: " << endl;
                cin >> theeName;
                cout << theeName << " has paid " << tl.havePaid(theeName) << endl << endl;
                break;
            }

            case 6:
            {
                pl = tl.FixPersons();
                pl.printOutAndFix();
                cout << endl;
                break;
            }

            default:
            {
                cout << "Please try again (0-6) " << endl;
            }
        }
    }

    return 0;
}

Open in new window

>> and I don't really understand how I could prevent it, how I should change my code so it doesn't do that.

In order to fix it, you have to first figure out where it crashes.

If you run your code in a debugger, it'll clearly point you to the line that caused the access violation. And once you know where it is, you can figure out what went wrong (again with the help of the debugger).
Avatar of rijku

ASKER

I finally figured out how to run the debugger and also I got this from the debugger. (Code Blocks also notifies about a "segmentation fault")
#0 00000000	0x00407050 in std::operator>><char, std::char_traits<char>, std::allocator<char> >() 
#1 00402685	Transaction::readATrans(this=0x22f600, is=@0x22fad4) 					(D:\gakusei\programming\TransactionJar_DynSecond.cpp	:181)
#2 00402CF5	TransactionsList::loadin(this=0x22f708, is=@0x22fad4) 					(D:\gakusei\programming\TransactionJar_DynSecond.cpp	:237)
#3 0040439D	main() 											(D:\gakusei\programming\TransactionJar_DynSecond.cpp	:473)

Open in new window

which considers the lines 181. in Transaction::readATrans
is >> friends[i];

Open in new window

237.in TranscationsList::loadin method.
while (t.readATrans(is))

Open in new window

and 473. in the main method.
tl.loadin(is);

Open in new window


About 181. im not really sure why it fails, all i can guess is that it bounds outside the array or that it's some problem with the memory allocation.
I guess that line 273 is the same problem as line 181.
Line 473 seems to be tracing back to line 181.
If I understand this right is line 181 where it crashes.
Am I anywhere right?
You've indeed identified the line where it crashes.

Now, have a close look at the Transaction::readATrans function.

You allocate memory for num_friends friends :

>>     friends = new string[num_friends];

But then you read in a new value of num_friends here :

>>     is >> date >> type >> name >> amount >> num_friends;

and you use this new value for storing data in the friends array :

>>     for (int i = 0; i < num_friends; i++)


What happens if the new num_friends value is bigger than the one used for allocating memory ?
Avatar of rijku

ASKER

Ok, thanks I solved that! Now I can see the "num_friends" and "friends" part of the Transactions when running.
However, I have continued with the other classes now, and encountered errors when I changed the other arrays which feels confusing.
#0 00402837	Transaction::assign(this=0x0, t=@0x22fbb0) 		cpp:221)
#1 00402F29	TransactionsList::addMore_TL(this=0x22fee8, t=@0x22fbb0)cpp:285)
#2 00402E4A	TransactionsList::loadin(this=0x22fee8, is=@0x22fcac) 	cpp:271)
#3 0040473A	main() 							cpp:584)

Open in new window

Line 221 is num_friends = t.num_friends; in Transaction::assign method, which was working before I changed the other arrays.
Line 285 is trans[numTrans].assign(t); in TransactionList::addMore_TL, which I previously changed with the Transaction class. And the other lines refer to Line 285. If I understand it right, is it that it refers wrong (e.g. this=0x22fee8, t=@0x22fbb0)?
Also I feel unsecure on which constructors and methods to use, I usually go with "the rule of three" but when I tried to make a assignment as in the Transaction class, i got errors
pers = new Person[num_persons]; // allocate memory.
        for (int i = 0; i < num_persons; i++)
            pers[i] = v;

Open in new window

in the third line, so dont know if im making anything wrong or if this constructor isn't neccessary in this class. Got the same problem when I tried it with a correlative constructor in the TransactionList class. However, at the moment I only have copy constructors.
I know that you helped me solve the initial problem I asked for, but if it's okay I would like further guidance, if not, say the word
>> #0 00402837      Transaction::assign(this=0x0, t=@0x22fbb0)             cpp:221)

That would indicate that the object for which the assign method is not valid (this=0x0).


>>             pers[ i ] = v;

Is v the right type ? Do you have an operator= for the Person class ?
Avatar of rijku

ASKER

>> Is v the right type ? Do you have an operator= for the Person class ?

I made an operator= in PersonList too and used the assignments inside it in a if(this != &pl), and it did stop bothering me now, and I hope it's a working way. I only have overloading assignment operators in the Transaction class now.

I've added a operator= in the Person class and I also had Segmentation fault, but, it was solved when I added this (Including the errors mentioned in my last post.).
const Person & Person::operator= (const Person &p)
{
    if(this != &p) // protects against invalid self-assignment.
    {
    }
    return *this;
}

Open in new window

Now, the choice 2 works, but the segfault "this.0x0" remains in choice 1. However, Im a bit unsure on what I should add in the if-statements brackets . I would like something like delete[] and new there, but i get a bit confused because there's no *array in the Person class

Additionally, does PersonList::addAnotherP method need some further development?
void PersonList::addAnotherP(Person pny)
{
    //pers[num_persons].assign(pny);
    pers[num_persons] = pny;
    num_persons++;
}

Open in new window

Because addMore_TL method had the commented part instead of the second line between the brackets. I've been figuring how I in that case would be able to add a assign method, but don't get it quite right, because of, again, that the class Person don't have an *array.
Im not sure what else could be changed,but it feels pretty obvious that I missed out on some copying business.. Because the result right now with the *pers included instead of the static one is only num_friends, and friends shown in the transactions, (choice 2 or ostream file) and when I include *trans nothing is in the transactions.

At the moment I have default constructor, destructor, operator= and copy constructor in all classes except Person that only have operator= as newly added stuff.