【问题标题】:Segmentation fault: 11 and malloc errors in C++ code分段错误:C++ 代码中的 11 和 malloc 错误
【发布时间】:2012-03-03 21:59:34
【问题描述】:

好的,所以我知道这段代码中可能有很多错误。我对动态内存分配、指针等很陌生。

头文件account.h是我们教授给我们的。我们被告知不要对 .h 文件进行任何更改。

实现文件是我写的。主要功能仅用于基本的初始测试。我们得到了另一个文件来实际测试帐户类的实现。

如果我不注释掉 cout 名称行,我会收到 seg fault 11 错误。 如果我这样做,它会打印帐号,但会抛出此错误:

Test(29976) malloc: * 对象 0x62c1aa18c9d8374 的错误:未分配被释放的指针* 在 malloc_error_break 中设置断点以进行调试
中止陷阱:6

任何帮助都将不胜感激!

这是头文件:

class account
{
public:
    typedef char* string;
    static const size_t MAX_NAME_SIZE = 15;
    // CONSTRUCTOR
    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 ostream& operator <<(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
};

这里是实现文件:

// File: account.cxx
// Author: Mike Travis
// Last Modified: Mar 3, 2012
// Description: implementation of Account class as prescribed by the file account.h

#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include "account.h"

using namespace std;

//Constructor

account::account(char* i_name, size_t i_acnum, size_t i_hsize){
    string *d_history;
    d_history = new string[i_hsize];

    for(int i = 0; i<i_hsize; i++){
        name[i] = i_name[i];
    }
    ac_number = i_acnum;
    history_size = i_hsize;
    history_count = 0; 
}


account::account(const account& ac){
    string *d_history;
    d_history = new string[ac.history_size];

    for( int i=0; i<ac.get_current_history_size(); i++){
        strcpy(d_history[i], history[i]);
    }

    strcpy(name,ac.get_name());
    ac_number = ac.get_account_number();
    history_size = ac.get_max_history_size();
    history_count = ac.get_current_history_size();
}

account::~account(){    delete [] history;  }

void account::set_name(char* new_name){                 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){
    strcpy(history[history_count], new_history);
    history_count++;
}

char* account::get_name() const {
    char* name_cpy;
    strcpy(name_cpy, name);
    return name_cpy;
}

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;   }
//string* account::get_history() const{                         return *history;        }


int main(){

    account test1("mike travis", 12345, 20);
    //cout<<"\nname: "<< test1.get_name();

    cout<<"\n\nacnum: "<<test1.get_account_number()<<"\n\n";

    return 0;
}

【问题讨论】:

  • 如果您正在编写 C++,您应该更喜欢 new/delete 而不是 malloc/free。而且你应该使用智能指针来管理事情,除非你真的知道自己在做什么。
  • 错误告诉你如何调试这个:“在 malloc_error_break 中设置断点来调试。”你做过吗?你发现了什么?
  • 如果你的老师给了你那个头文件,请告诉他应该接a good C++ book,不要教学生写质量差的C++代码。正确实现该类是不可能的:它拥有资源但不提供用户声明的复制赋值运算符。
  • 头文件太糟糕了,甚至都不好笑。此外,您似乎对此一无所知,我不知道要开始。看看你的 get_name 实现。你认为这是在做什么?首先你写入一个未初始化的指针,然后你返回它的值。但是你为什么要在那里复制呢?哦,我明白了,您的教授似乎不知道 const 的正确性。结论:请分别学习各个部分并提出较小的问题。 -- 有了这个头文件,不可能写出干净的代码。只需查看 get_name() 声明即可。
  • 不,我没有在 malloc_error_break 中设置断点...我使用 mac 终端中的 g++ 进行编译,不知道如何在 malloc_error_break 中设置符号断点...有人知道我会怎么做吗?

标签: c++ segmentation-fault malloc


【解决方案1】:

account 的析构函数中,删除history 数组。但是,在构造函数中,您分配(并泄漏)了一个存储在局部变量d_history 中的数组。您大概想将其分配给成员变量 history - 因为您没有,如果您到达析构函数,它会给您一个错误,说您正在释放 history 但从未分配过它。

复制构造函数中也有类似的错误。

您的代码中还有其他错误,我假设您会在执行过程中发现这些错误 - 例如,get_name() 将无法正常工作。我怀疑头文件在这里没有帮助,但如果你不应该改变它,那就没什么可做的了。

【讨论】:

    【解决方案2】:

    我已经为您编写了一些代码并纠正了史诗般的错误(即使是在头文件中,抱歉 ;))。它仍然非常丑陋和 c-ish,但也许你可以通过阅读它学到一些东西:

    #include <cstddef>
    #include <ostream>
    
    class account
    {
        // The whole class makes no sense, since it has no useful
        // member function or anything like this.
        // Furthermore, the class provides almost full access to all its member variables.
        // At this point one could just make everything public.
    
        // This is not even exception safe when the constructor throws.
        // A good implementation would use history_entry and history classes, 
        // together with std::string and std::vector/std::deque
        // And it would provide some sort of functionality. ;)
    
    public:
      account(const char* name, unsigned number, std::size_t history_max_size);
      account(const account& other);
      ~account();
    
        const char* name() const;
      unsigned number() const;
      double balance() const;
        const char* const* history() const;
        std::size_t history_size() const;
      unsigned history_max_size() const;
    
      void set_name(const char* new_name);
      void set_number(unsigned new_number);
      void set_balance(double new_balance);
      void add_history(const char* new_history);
    
    private:
      char* name_;
      unsigned number_;
      double balance_;
      char** history_;
        std::size_t history_size_;
        const std::size_t history_max_size_;
    };
    
    std::ostream& operator << (std::ostream& stream, const account& a);
    
    
    #include <cassert>
    #include <cstring>
    
    account::account(const char* name, unsigned number, std::size_t history_max_size)
        : name_(0)
        , number_(number)
        , balance_(0.0)
        , history_(new char*[history_max_size])
        , history_size_(0)
        , history_max_size_(history_max_size)
    {
        assert(name != 0);
        assert(history_max_size != 0);
        set_name(name);
    }
    
    account::account(const account& other)
        : name_(0)
        , number_(other.number_)
        , balance_(other.balance_)
        , history_(new char*[other.history_max_size_])
        , history_size_(other.history_size_)
        , history_max_size_(other.history_max_size_)
    {
        set_name(other.name_);
        for (std::size_t i = 0; i != other.history_size_; ++i)
        {
            history_[i] = new char[std::strlen(other.history_[i]) + 1];
            strcpy(history_[i], other.history_[i]);
        }
    }
    
    account::~account()
    {
        delete[] name_;
    
        for (std::size_t i = 0; i != history_size_; ++i)
            delete[] history_[i];
        delete[] history_;
    }
    
    const char* account::name() const
    {
        return name_;
    }
    
    unsigned account::number() const
    {
        return number_;
    }
    
    double account::balance() const
    {
        return balance_;
    }
    
    const char* const* account::history() const
    {
        return history_;
    }
    
    std::size_t account::history_size() const
    {
        return history_size_;
    }
    
    unsigned account::history_max_size() const
    {
        return history_max_size_;
    }
    
    void account::set_name(const char* new_name)
    {
        if (name_)
            delete[] name_;
    
        name_ = new char[std::strlen(new_name) + 1];
        std::strcpy(name_, new_name);
    }
    
    void account::set_number(unsigned new_number)
    {
        number_ = new_number;
    }
    
    void account::set_balance(double new_balance)
    {
        balance_ = new_balance;
    }
    
    void account::add_history(const char* new_history)
    {
        if (history_size_ == history_max_size_)
        {
            delete[] history_[0]; // delete oldest entry
            for (std::size_t i = 0; i != history_size_ - 1; ++i)
                history_[i] = history_[i + 1];
            --history_size_;
        }
    
        history_[history_size_] = new char[strlen(new_history) + 1];
        std::strcpy(history_[history_size_], new_history);
        ++history_size_;
    }
    
    std::ostream& operator << (std::ostream& stream, const account& a)
    {
        return stream << "account [name: " << a.name() << ", number: " 
            << a.number() << ", balance: " << a.balance() << ']';
    }
    
    
    #include <iostream>
    
    int main()
    {
        account a("Hello!", 500, 5);
        a.set_balance(12.546);
        for (int i = 50; i--; )
            a.add_history("Yaaay..");
        //account b = a;
        std::cout << a << '\n';
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-16
      • 2019-01-22
      • 1970-01-01
      • 2021-09-17
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多