奇怪的段错误

时间:2012-03-12 03:13:23

标签: c++ segmentation-fault

对不起,我知道这是Stack Overflow上的第十九段错误帖子,但我已经尝试了几天修复这段代码而且我很难过,所以我决定转向你们。我希望你能帮忙!

无论如何,我在这段代码中得到了一个奇怪的段错误:

account.h(注意,根据作业,我不允许以任何方式修改account.h文件。)

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和GDB都说*(open [i])未初始化。这是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

它从主要地方转移到bankledgrer::close_account,再转移到bankledger::lookup,然后它在if(open[i]->get_account_number() == accnum)

崩溃

如果我在该行之前粘贴cout << *(open[i]),则会将其打印出来。 我担心我不知所措。任何帮助,将不胜感激。如果您希望我包含头文件或澄清任何内容,请告诉我。

PS。另外,我知道这段代码非常C,但这就是我教授想要它的方式,即使它是一个C ++类。去搞清楚。 :\

1 个答案:

答案 0 :(得分:4)

在这种方法中:

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;
        }
    }
}

您假设至少与未结账户金额相同的已结账户数量。你应该在不同的循环中迭代打开和关闭的数组,因为你试图访问closed [i],i = 1,2,3 ......,而closed不包含任何有效的指针(只是一堆NULL指针)。这应该有用(除非我遗漏了别的东西):

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;
}