程序崩溃:(1)矩阵乘法; (2)矩阵加法/减法失败

时间:2014-10-05 01:05:33

标签: c++ multidimensional-array matrix-multiplication dynamic-memory-allocation

简而言之,我被赋予了创建一个动态分配内存以形成int值矩阵的类的任务。

该类的一部分是执行基本矩阵计算的成员函数 - 加法,减法和乘法。所有东西都编译(至少在我的末尾),但是当我使用驱动程序来测试乘法部分时,它会一直崩溃。

我正在使用Codeblocks作为我的IDE,并且试图弄清楚调试器没有太多运气。似乎计算完成了(具有正确的值),但事情在某处发生了可怕的错误。

为清楚起见,Matrix类的每个对象都有以下成员数据:

private:
    int rows;
    int cols;
    int **element;

下面是实现文件的片段,其中重载的运算符*被充实。在执行乘法的循环之前temp.element [i] [x]被设置为'0'的部分被注释掉了,因为默认构造函数已经将所有值都设置为'0' - 当我把它放入时我忘记了本来。当我没有注释掉它时它没有用。

在测试中,我使用了一个2x3阵列和一个3x2阵列。

Matrix Matrix::operator*(const Matrix &aMatrix) const
{
    if(cols == aMatrix.rows)
    {
        Matrix temp(rows, aMatrix.cols);
        for(int i = 0; i < rows; i++)
        {
            for(int x = 0; x < aMatrix.cols; x++)
            {
                //temp.element[i][x] = 0;
                for(int n = 0; n < cols; n++)
                {
                    temp.element[i][x] += (element[i][n]
                                       * aMatrix.element[n][x]);
                }
            }
        }
        return temp;
    }
    else
    {
        cerr << "Matrix multiplication failed -- incompatible matrix sizes."
             << endl;
        return *this;
    }
}

在尝试查看代码并发现错误时,我开始重新检查我的其他功能。似乎加法和减法都有效,但如果矩阵不相容(即尝试添加2x3和4x4),程序将关闭。

下面是添加的片段(在最终循环中,减法几乎相同' - '而不是'+'。

Matrix Matrix::operator+(const Matrix &aMatrix) const
{
    if(rows == aMatrix.rows && cols == aMatrix.cols)
    {
        Matrix temp(rows, cols);
        for(int i = 0; i < rows; i++)
        {
            for(int x = 0; x < cols; x++)
            {
                temp.element[i][x] = element[i][x] + aMatrix.element[i][x];
            }
        }
        return temp;
    }
    else
    {
        cerr << "Undefined matrix addition -- matrices are different sizes."
             << endl;
        return *this;
    }
}

感谢任何帮助或见解。感谢。

已编辑:添加了重载的赋值运算符,复制构造函数和析构函数代码。

下面是重载的赋值运算符:

Matrix Matrix::operator=(Matrix aMatrix)
{
    if(this != &aMatrix)
    {
        for(int i = 0; i < rows; i++)
        {
            delete [] element[i];
            element[i] = NULL;
        }
        delete [] element;
        rows = aMatrix.rows;
        cols = aMatrix.cols;
        element = new int* [rows];
        for(int i = 0; i < rows; i++)
        {
            element[i] = new int [cols];
            for (int x = 0; x < cols; x++)
            {
                element[i][x] = aMatrix.element[i][x];
            }
        }
    }
    return *this;
}

下面是复制构造函数:

Matrix::Matrix(const Matrix &aMatrix)
{
    rows = aMatrix.rows;
    cols = aMatrix.cols;
    element = new int* [rows];
    for(int i = 0; i < rows; i++)
    {
        element[i] = new int [cols];
        for (int x = 0; x < cols; x++)
        {
            element[i][x] = aMatrix.element[i][x];
        }
    }
}

析构函数:

Matrix::~Matrix()
{
    for(int i = 0; i < rows; i++)
    {
        delete [] element[i];
        element[i] = NULL:
    }
    delete [] element;
    element = NULL;
}

2 个答案:

答案 0 :(得分:0)

您需要弄清楚这些操作的语法和语义。从你的例子看起来好像你想要的东西:

Matrix lhs = <something>;
Matrix rhs = <something>;
Matrix result = lhs * rhs;

到&#34;只是工作&#34;。虽然这在语法上可能很好,但您需要考虑如果lhs和rhs不能相乘(或添加等)会发生什么。您还需要担心正确设置结果。你不能只返回一个由多个行,列和一组指针组成的结构&#34;并期望不会遇到可怕的内存管理问题。

使产品消失的原因是什么?什么时候超出范围? C ++不是一个非常好的线性代数语言。

您需要做的第一个决定是,您是否打算为无效操作抛出异常,或者返回一些错误的指示,可能是bool和const char *来显示错误消息。

然后你可能应该尝试编写一个带有结果引用和2个操作数引用的函数,如果矩阵支持该操作,则只需要正确的基本代数。 (我还没有提到你的Matrix只是一个整数矩阵。)

在&#34;现实生活&#34;中,您可能会尝试找到管理所有这些的开源标准解决方案,因为需要非常小心地管理数值运算。

有人甚至可能认为这是几十年前在Fortran中已经解决的问题,直到今天,如果性能成为一个问题,那么潜在的计算很可能是在Fortran中,或者是来自C的端口的库。

答案 1 :(得分:0)

您发布了一个复制构造函数和赋值运算符。您的任务操作员有4个主要问题:

  1. 您应该通过const引用传递参数,而不是通过值传递。
  2. 您应该返回对当前对象的引用,而不是全新的对象。
  3. 如果new在分配期间抛出异常,则您通过事先删除内存来搞乱对象。
  4. 多余。复制构造函数中会显示相同的代码。
  5. 您可以根据复制构造函数重写赋值运算符并缓解这些问题:

    #include <algorithm>
    //...
    Matrix& Matrix::operator=(const Matrix& aMatrix)
    {
        Matrix temp(aMatrix);
        swap(*this, temp);
        return *this;
    }
    
    void Matrix::swap(Matrix& left, Matrix& right)
    {
       std::swap(left.rows, right.rows);
       std::swap(left.cols, right.cols);
       std::swap(left.element, right.element);
    }
    

    您只需将swap函数添加到Matrix类(可能作为private)函数。

    上面的代码使用了copy/swap成语,并缓解了我提到的所有问题。如果正确编写了复制构造函数和析构函数,这将起作用。关于这个习惯用法有很多线索,但基本上发生的事情就是:

    1. 从传入的对象创建临时对象。如果new投掷出现问题,则this不会搞砸。

    2. 与临时成员交换this个成员。这将使用临时数据刷新this对象,并为临时提供我们不再需要的旧数据。

    3. 让临时骰子用我们从this给出的旧东西。

    4. 返回this

    5. 至于其他方面,如果两个矩阵不能相乘,那么就抛出异常。不要返回虚假或混淆的Matrix对象,而这些对象并不能真正反映发生的事情。

      此外,您应首先编写运算符+=*=。为什么?因为实施运算符+*分别可以+=*=加上,所以加上+=和{{ 1}}可用。

      例如:

      *=

      因此,如果Matrix大小是个问题,operator +和+ =将抛出异常。请注意运算符Matrix& Matrix::operator+=(const Matrix &aMatrix) { if(rows != aMatrix.rows || cols != aMatrix.cols) throw SomeException; for(int i = 0; i < rows; i++) { for(int x = 0; x < cols; x++) element[i][x] += aMatrix.element[i][x]; } return *this; } Matrix Matrix::operator+(const Matrix &aMatrix) { Matrix temp(*this); temp += aMatrix; return temp; } 如何按+实现。采用与+=*以及*=-相同的方法。