Reputation: 410
I'm sorry, I know this is the umpteenth seg fault post on Stack Overflow, but I've tried for a few days to fix this code and I'm stumped, so I decided to turn to you guys. I hope you can help!
Anyway, I'm getting a strange segfault in this code:
account.h (Note, I'm not allowed modify the account.h file in anyway, as per the assignment. :)
class account
{
public:
typedef char* string;
static const size_t MAX_NAME_SIZE = 15;
// CONSTRUCTOR
//account();
account (char* i_name, size_t i_acnum, size_t i_hsize);
account (const account& ac);
// DESTRUCTOR
~account ( );
// MODIFICATION MEMBER FUNCTIONS
void set_name(char* new_name);
void set_account_number(size_t new_acnum);
void set_balance(double new_balance);
void add_history(char* new_history);
// CONSTANT MEMBER FUNCTIONS
char* get_name () const;
size_t get_account_number ( ) const;
double get_balance( ) const;
size_t get_max_history_size( ) const;
size_t get_current_history_size ( ) const;
string* get_history() const;
friend std::ostream& operator <<(std::ostream& outs, const account& target);
private:
char name[MAX_NAME_SIZE+1]; //name of the account holder
size_t ac_number; //account number
double balance; //current account balance
string* history; //Array to store history of transactions
size_t history_size; //Maximum size of transaction history
size_t history_count; //Current size of transaction history
};
account.cxx:
#include <string.h>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include "account.h"
using namespace std;
account::account(char* i_name, size_t i_acnum, size_t i_hsize)
{
assert(strlen(i_name) <= MAX_NAME_SIZE);
strcpy(name, i_name);
ac_number = i_acnum;
history_size = i_hsize;
balance = 0;
history_count = 0;
history = new string[history_size];
}
account::account(const account& ac)
{
strcpy(name, ac.name);
ac_number = ac.ac_number;
balance = ac.balance;
history = new string[ac.history_size];
for(size_t i = 0; i < ac.history_count; i++)
{
history[i] = new char[strlen(ac.history[i]) + 1];
strcpy(history[i], ac.history[i]);
}
history_count = ac.history_count;
history_size = ac.history_size;
}
account::~account()
{
delete[] history;
}
void account::set_name(char* new_name)
{
assert(strlen(new_name) <= MAX_NAME_SIZE);
strcpy(name, new_name);
}
void account::set_account_number(size_t new_acnum) {ac_number = new_acnum;}
void account::set_balance(double new_balance) {balance = new_balance;}
void account::add_history(char* new_history)
{
assert(history_count < history_size);
history[history_count] = new char[strlen(new_history) + 1];
strcpy(history[history_count], new_history);
history_count++;
}
char* account::get_name() const
{
char* blah = new char[MAX_NAME_SIZE + 1];
strcpy(blah, name);
return blah;
}
size_t account::get_account_number ( ) const {return ac_number;}
double account::get_balance( ) const{return balance;}
size_t account::get_max_history_size( ) const {return history_size;}
size_t account::get_current_history_size ( ) const {return history_count;}
account::string* account::get_history() const
{
string* blah = new string[history_size];
for(size_t i = 0; i < history_count; i++)
{
blah[i] = new char[strlen(history[i]) + 1];
strcpy(blah[i], history[i]);
}
return blah;
}
std::ostream& operator<< (std::ostream& outs, const account& target)
{
outs << "Name: " << target.name << "\n"
<< "Account Number: " << target.ac_number << "\n"
<< "Balance: " << "$" << target.balance << "\n"
<< "History: ";
for(size_t i = 0; i < target.history_count; i++)
{
outs << target.history[i] << "\n";
}
outs << "Current History Size: " << target.history_count << "\n";
outs << "Max History Size: " << target.history_size << "\n";
return outs;
}
bankledger.h
class bank_ledger
{
public:
static const int MAX_ACC_SIZE = 15;
bank_ledger(int mo, int mc);
bank_ledger(const bank_ledger& copyledger);
~bank_ledger();
void create_account(char* i_name, size_t i_acnum, size_t i_hsize);
void close_account(double accnum);
double balance_of(double accnum);
void deposit(double accnum, double money);
void withdraw(double accnum, double money);
void transfer(double accnum1, double accnum2, double money);
void print_account_history(double accnum);
void print_account_details(double accnum);
void print_current_details();
void print_closed_details();
account* lookup(double accnum);
private:
account** open;
account** closed;
int max_open;
int max_closed;
int num_open;
int num_closed;
};
bankledger.cxx:
#include <cstdlib>
#include <iostream>
#include <cassert>
#include "account.h"
#include "bank_ledger.h"
using namespace std;
bank_ledger::bank_ledger(int mo = 30, int mc = 30)
{
max_open = mo;
max_closed = mc;
open = new account*[max_open];
closed = new account*[max_closed];
num_open = 0;
num_closed = 0;
}
bank_ledger::bank_ledger(const bank_ledger& copyledger)
{
int i;
max_open = copyledger.max_open;
max_closed = copyledger.max_closed;
num_open = copyledger.num_open;
num_closed = copyledger.num_closed;
open = new account*[num_open];
closed = new account*[num_closed];
for(i = 0; i < max_open; i++)
{
if (i < num_open)
open[i] = copyledger.open[i];
}
for(i = 0; i < max_closed; i++)
{
if (i < num_closed)
closed[i] = copyledger.closed[i];
}
}
bank_ledger::~bank_ledger()
{
for(int i = 0; i < num_open; i++)
{
delete open[i];
}
for(int i = 0; i < num_closed; i++)
{
delete closed[i];
}
delete[] open;
delete[] closed;
}
account* bank_ledger::lookup(double accnum)
{
for(int i = 0; i < num_open; i++)
{
if(open[i]->get_account_number() == accnum)
{
return *open + i;
}
if(closed[i]->get_account_number() == accnum)
{
return *closed + i;
}
}
}
void bank_ledger::create_account(char* i_name, size_t i_acnum, size_t i_hsize)
{
assert(num_open < max_open);
open[num_open] = new account(i_name, i_acnum, i_hsize);
open[num_open]->add_history("Account Created");
num_open++;
}
void bank_ledger::close_account(double accnum)
{
int i;
double temp = -1;
cout << *(open[0]) << endl << "Good Idea" << endl;
account* acc = lookup(accnum);
for(i = 0; i < num_open; i++)
{
if(open[i]->get_account_number() == acc->get_account_number())
{
temp = i;
closed[num_closed] = open[i];
for(i = temp; i < num_open - 1; i++)
{
open[i] = open[i+1];
}
closed[num_closed]->add_history("Account Closed");
num_open--;
num_closed++;
return;
}
}
}
double bank_ledger::balance_of(double accnum)
{
return lookup(accnum)->get_balance();
}
void bank_ledger::deposit(double accnum, double money)
{
account* acc = lookup(accnum);
acc->set_balance(acc->get_balance() + money);
acc->add_history("Deposited $");
}
void bank_ledger::withdraw(double accnum, double money)
{
account* acc = lookup(accnum);
acc->set_balance(acc->get_balance() - money);
acc->add_history("Withdrew $");
}
void bank_ledger::transfer(double accnum1, double accnum2, double money)
{
withdraw(accnum2, money);
deposit(accnum1, money);
}
void bank_ledger::print_account_history(double accnum)
{
account* acc = lookup(accnum);
account::string *hist = acc->get_history();
cout << "History of " << acc->get_name() << "'s account: " << endl;
for (int i = 0; i < acc->get_current_history_size(); i++) cout << hist[i] << endl;
}
void bank_ledger::print_account_details(double accnum)
{
account* acc = lookup(accnum);
cout << *acc;
cout << "\n";
}
void bank_ledger::print_current_details()
{
for(int i = 0; i < num_open; i++)
{
cout << *open[i] << "\n";
}
}
void bank_ledger::print_closed_details()
{
for(int i = 0; i < num_closed; i++)
{
cout << *closed[i] << "\n";
}
cout << "\n";
}
sample_test_input2.cxx
#include <cstdlib>
#include <iostream>
#include "account.h"
#include "bank_ledger.h"
using namespace std;
int main()
{
bank_ledger bl(30, 30);
bl.create_account("name1", 1, 30);
bl.create_account("name2", 2, 30);
bl.create_account("name3", 3, 30);
bl.create_account("name4", 4, 30);
bl.print_current_details();
bl.close_account(2);
return 0;
}
Valgrind and GDB both say that *(open[i]) is uninitialized. Here's the exact output from Valgrind:
==7082== Use of uninitialised value of size 8
==7082== at 0x1000018C6: account::get_account_number() const (account.cxx:74)
==7082== by 0x10000246B: bank_ledger::lookup(double) (bank_ledger.cxx:85)
==7082== by 0x1000027D0: bank_ledger::close_account(double) (bank_ledger.cxx:105)
==7082== by 0x100003117: main (sample_test_input2.cxx:17)
==7082==
==7082== Invalid read of size 8
==7082== at 0x1000018C6: account::get_account_number() const (account.cxx:74)
==7082== by 0x10000246B: bank_ledger::lookup(double) (bank_ledger.cxx:85)
==7082== by 0x1000027D0: bank_ledger::close_account(double) (bank_ledger.cxx:105)
==7082== by 0x100003117: main (sample_test_input2.cxx:17)
==7082== Address 0x10 is not stack'd, malloc'd or (recently) free'd
It goes from main to bankledgrer::close_account
, to bankledger::lookup
and then it crashes at if(open[i]->get_account_number() == accnum)
If I stick cout << *(open[i])
right before that line, it prints it out fine.
I'm afraid I'm at a loss. Any help would be appreciated. If you want me to include the header files, or clarify anything please let me know.
PS. Also, I know this code is very C, but that's the way my professor wants it, even though it's a C++ class. Go figure. :\
Upvotes: 4
Views: 243
Reputation: 21900
In this method:
account* bank_ledger::lookup(double accnum)
{
for(int i = 0; i < num_open; i++)
{
if(open[i]->get_account_number() == accnum)
{
return *open + i;
}
if(closed[i]->get_account_number() == accnum)
{
return *closed + i;
}
}
}
You are assuming there are at least the same amount of closed accounts than the amount of open accounts. You should iterate through the open and closed arrays in different loops, since you're trying to access closed[i], being i = 1,2,3..., and closed does not contain any valid pointers(just a bunch of NULL pointers). This should work(unless i'm missing something else):
account* bank_ledger::lookup(double accnum) {
for(int i = 0; i < num_open; i++) {
if(open[i]->get_account_number() == accnum)
return open[i];
}
for(int i = 0; i < num_closed; i++) {
if(closed[i]->get_account_number() == accnum)
return closed[i];
}
return 0;
}
Upvotes: 4