为啥我的代码结果显示分段错误(核心转储)?

Posted

技术标签:

【中文标题】为啥我的代码结果显示分段错误(核心转储)?【英文标题】:why is my code result showing Segmentation fault (core dumped)?为什么我的代码结果显示分段错误(核心转储)? 【发布时间】:2020-12-19 09:58:48 【问题描述】:

我创建了具有构造函数和运算符 + 重载以添加两个矩阵的类 mat(矩阵),但是当我编译并运行我的代码时,一切正常,直到我初始化我的 m1、m2..然后结果是“分段错误(核心转储)”。 我不明白为什么它显示它? 我没有在此处发布 ostream& 运算符

class mat
    int r,c;
    float **p;
    public:
    mat()
    mat(int,int);
    mat(int,int,float);
    void initialize();
    mat operator+(mat); //defined
    friend ostream& operator<<(ostream&,mat&);  
;
void mat :: initialize(void)
    int i,j;
    cout<<"\nEnter the elements : ";
    for(i=0;i<r;++i)
        for(j=0;j<c;++j)
            cin>>p[i][j];
        
    
    return;

mat mat :: operator+(mat x)
    mat tmp;
    int i,j;
    for(i=0;i<r;++i)
        for(j=0;j<c;++j)
            tmp.p[i][j]=(p[i][j])+(x.p[i][j]);
        
    
    return tmp;

mat :: mat (int a, int b) 
    r=a;
    c=b;
    p=new float*[r];
    for(int i=0; i<r; ++i)
        p[i]=new float[c];
    

mat :: mat (int a, int b, float t) 
    r=a;
    c=b;
    p=new float*[r];
    for(int i=0; i<r; ++i)
        p[i]=new float[c];
    
    
      for(int i=0;i<r;++i)
        for(int j=0;j<c;++j)
            p[i][j]=t;
        
    

int main()
    mat m1(3,3),m2(3,3),m3(3,3,0);
    cout<<"\nInitialize M1";
    m1.initialize();
    cout<<"\nInitialize M2";
    m2.initialize();
    m3=m1+m2;
    cout<<m3;
    return(0);

我是编码新手。请用简单的语言帮助我。

【问题讨论】:

您的mat 类不能安全地复制或分配,但您正在operator + 中重新使用它。这是rule of 3 违规(请参阅该链接的管理资源部分)。要么编写必要的用户定义的复制构造函数、赋值运算符和析构函数,要么使用std::vector&lt;std::vector&lt;float&gt;&gt; p;。如果您执行后者,您的代码可能会神奇地开始工作。 例如mat tmp; 你复制到 tmp 虽然你还没有分配任何空间 tmp.p。使用 std::vector 代替,那么您的许多问题都会消失。 阅读this C++ reference 然后阅读你的C++ 编译器的文档,也许是GCC。如果您使用 GCC 编译带有所有警告和调试信息的代码,那么使用 g++ -Wall -Wextra -g。然后阅读调试器的文档(可能是GDB...)。最后使用gdb 来了解你的程序的行为。从现有的开源 C++ 软件中汲取灵感,例如fish、FLTK、RefPerSys 您也未能在mat 默认构造函数中初始化您的成员变量。基本上,您的 mat 课程以几种不同的方式被破坏,甚至考虑为它编写 operator + 还为时过早。 @AndersK 非常感谢。它奏效了。 ...我意识到我在这个过程中犯了什么错误。 【参考方案1】:

operator+ 中的mat tmp; 未初始化。它使用默认的无参数构造函数,它什么都不做,特别是,不会将 p 指针设置为任何内容,这会在您尝试分配其内容时导致分段错误。一个好的 operator+ 应该检查两个矩阵是否具有相同的维度,并使用双参数构造函数创建结果矩阵。

这应该回答了这个问题,但我也会详细说明 PaulMcKenzie 的评论,因为它很重要。

这样的类在分配、移动或销毁时没有定义的特殊行为,这在处理原始指针时是不可接受的。例如,当您将此类的一个对象分配给另一个对象时,字段被简单地复制,这意味着两个对象共享相同的p 指针,这可能不是您想要的。您的对象在销毁时也不会清理其内存,这意味着您的程序中有多个内存泄漏。

为了拥有一个使用原始指针的功能类,您需要

mat(const&amp; mat other); - 复制构造函数

mat&amp; mat::operator=(const&amp; mat other); - 复制赋值运算符

mat(mat&amp;&amp; other) noexcept; - 移动构造函数(C++11 及以上)

mat&amp; mat::operator=(mat&amp;&amp; other) noexcept; - 移动赋值运算符(C++11 及以上)

~mat(); - 析构函数

如果您不提供析构函数,则每次销毁此类的对象时都会发生内存泄漏。如果你提供析构函数但复制/移动保持默认,它会崩溃,因为在你复制或移动一个对象后,两个对象将持有相同的p指针,并且在两个对象被销毁后,指针将被释放两次,这会导致崩溃。

按照 PaulMcKenzie 的建议,一个简单的解决方法是使用 std::vector,它已为您完成所有内存管理。

如果你想自己写,请查阅“0规则”/“3规则”/“5规则”。

在半相关的注释中,mat mat :: operator+(mat x) 被声明为错误,因为它创建了参数的不必要副本并且不是 const。声明它的正确方法是mat mat :: operator+(const mat&amp; x) const,它将参数作为 const 引用传递,并且本身也是 const,这意味着它可以用于 const 变量。

【讨论】:

以上是关于为啥我的代码结果显示分段错误(核心转储)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的代码会出现分段/核心转储错误?

为啥在编译我的代码C(linux)时出现分段错误(核心转储)[关闭]

为啥我得到分段(核心转储)?

为啥我在 C 中收到警告“分段错误,核心转储”

在我的模板类示例中,出现“分段错误(核心转储)”错误

运行我的代码时出现分段错误(核心转储)问题