为什么我的C++程序有时会在离开方法时崩溃

Why does my C++ program sometimes crash upon leaving a method

本文关键字:离开 方法 崩溃 为什么 C++ 程序 我的      更新时间:2023-10-16

我正在尝试编写一个小库来实现矩阵和对它们的一些基本操作。现在我正在尝试实现 LU 分解。问题是我的程序有时运行没有问题,有时它会提前终止,窗口只是说"测试.exe已经超过工作"。

我正在使用具有以下选项的 g++ 进行编译:

g++  "./Lineair Algebra/Matrix.cpp" "./Lineair Algebra/Determinant.cpp" test.cpp -g -lm -std=c++11 -o test.exe

包含文件行列式.cpp,因为我打算使用分解来计算大小为> 3 的行列式。

调用分解的代码正在测试中.cpp:测试.cpp:

#include "./Lineair Algebra/Matrix.hpp"
#include "./Lineair Algebra/Determinant.hpp"
int main (void)
{
    Matrix n (4,4);
    Matrix& nRef = n;
    n.set(0,0,2);
    n.set(0,3,1);
    n.set(2,0,-2);
    n.set(3,0,4);
    n.set(1,1,1);
    n.set(2,1,-3);
    n.set(3,1,-4);
    n.set(1,2,3);
    n.set(2,2,-5);
    n.set(3,2,4);
    n.set(0,3,1);
    n.set(1,3,-3);
    n.set(2,3,2);
    n.set(3,3,6);
    Matrix tmp1 (4,4);
    Matrix tmp2 (4,4);
    Matrix& tmp1Ref = tmp1;
    Matrix& tmp2Ref = tmp2;
    n.print();
    cout << "Decomposing" << endl;
    n.LUDecompose(tmp1Ref,tmp2Ref);
    cout << "Test.cpp regained control" << endl;
    n.print();
    tmp1.print();
    tmp2.print();
    cout << "Done printing, returning 0 from test.cpp" << endl;
    return 0;
}

矩阵.hpp:

#ifndef MATRIX_HPP
#define MATRIX_HPP
#include <iostream>
#include <vector>
using  namespace std;
typedef vector< vector<double> > Table;
class Matrix
{
    private:
        Table array;
        int rows;
        int cols;
    public:
        Matrix();
        Matrix(int r, int c);
        Matrix(Table t);
        ~Matrix(void);
        //Matrix (double** dp, size_t r, size_t c);
        Matrix operator+ (Matrix m);
        Matrix operator+ (double d);
        Matrix operator- (Matrix m);
        Matrix operator- (double d);
        Matrix operator* (Matrix m);
        Matrix operator* (double d);
        void operator*= (double d);
        Matrix operator/ (double d);
        void operator/= (double d);
        bool operator== (Matrix m);
        bool operator!= (Matrix m);
        bool isSquare () const;
        bool isRow () const;
        bool isCol () const;
        int getElements () const;
        int getRows() const;
        int getCols() const;
        int getSize () const;
        double get(int row, int col) const;
        void getSubMatrix (int rowFrom, int colFrom, int rowTo, int colTo, Matrix& dest) const;
        void getTable (Table& t) const;
        int getRow (int row, Matrix& dest) const;
        int getCol (int col, Matrix& dest) const;
        void set(int row, int col, double value);
        void set (Table& t);
        void expand (int r, int c);
        int addRows (int row, const Matrix& rrm);
        int addCols (int col, const Matrix& rcm);
        void gaussEliminate (Matrix& lower, Matrix& upper);
        int LUDecompose (Matrix& l, Matrix& u);
        int transpose (Matrix& dest);
        void print ();
};
#endif

Matrix.cpp 大约有 600 行长,所以我将尝试只发布必要的:

矩阵.cpp:构造函数和析构函数(仅用于调试)

#include <iostream>
#include <vector>
#include "Matrix.hpp"
using  namespace std;
typedef vector< vector<double> > Table;
Matrix::Matrix()
{
    array = Table (1, vector <double> (1));
    array[0][0] = 0;
}
Matrix::Matrix(int r, int c)
{
    array = Table (c, vector <double> (r));
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            this->set(i, j, 0);
        }
    }
}
Matrix::Matrix(Table t) : array(t) {}
Matrix::~Matrix(void)
{
    cout << "Deleting matrix" << endl;
}

矩阵.cpp:LUD组合方法

int Matrix::LUDecompose (Matrix& refLower, Matrix& refUpper)
{
    if (!this->isSquare())
    {
        cout << "Given matrix is not a square matrix" << endl;
        return -1;
    }
    else
    {
        double c = 0;
        Matrix rowMatrix (1,this->getCols());
        Matrix& refRowMatrix = rowMatrix;
        refUpper = *this;
        for (int i = 1; i < this->getRows(); i++)
        {
            for (int j = 0; j < i; j++)
            {
                if (i >= j)
                {
                    refUpper.getRow(j,refRowMatrix);
                    rowMatrix *= refUpper.get(i,j);
                    rowMatrix /= refUpper.get(j,j);
                    rowMatrix *= -1.0;
                    c = refUpper.get(i,j) / refUpper.get(j,j);
                    refUpper.addRows(i,refRowMatrix);
                    refLower.set(i, j, c);
                    cout << "Leaving if statement" << endl;
                }
                cout << "Leaving inner for loop" << endl;
            }
            cout << "Leaving outer for loop" << endl;
        }
        for (int i = 0; i < this->getRows(); i++)
        {
            refLower.set(i,i,1);
        }
        cout << "Returning 0 from LUDecompose" << endl;
        return 0;
    }
}
现在我知道那里有库为我

做这件事,但这不是真正的重点,我只是想在这里学习。还要记住,我主要是自学成才的,所以我的代码可能不符合(某些人的)专业标准。

当我在 gdb 之外运行此代码时,这是我得到的输出:

Deleting matrix
Deleting matrix
[2      0       0       1       ]
[0      1       3       -3      ]
[-2     -3      -5      2       ]
[4      -4      4       6       ]
Decomposing
Deleting matrix
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Returning 0 from LUDecompose
Deleting matrix
Test.cpp regained control
[2      0       0       1       ]
[0      1       3       -3      ]
[-2     -3      -5      2       ]
[4      -4      4       6       ]

[1      0       0       0       ]
[0      1       0       0       ]
[-1     -3      1       0       ]
[2      -4      4       1       ]

[2      0       0       1       ]
[0      1       3       -3      ]
[0      0       4       -6      ]
[0      0       0       16      ]
Done printing, returning 0 from test.cpp
Deleting matrix
Deleting matrix
Deleting matrix

对于成功运行,或以下操作用于不成功的运行:

Deleting matrix
Deleting matrix
[2      0       0       1       ]
[0      1       3       -3      ]
[-2     -3      -5      2       ]
[4      -4      4       6       ]
Decomposing
Deleting matrix
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Returning 0 from LUDecompose
Deleting matrix

从 GDB 运行代码时,它总是崩溃,并且 GDB 产生以下输出:

[New Thread 1584.0x8b8]
[New Thread 1584.0xdb8]
[New Thread 1584.0x13fc]
[New Thread 1584.0x10b8]
Deleting matrix
Deleting matrix
[2      0       0       1       ]
[0      1       3       -3      ]
[-2     -3      -5      2       ]
[4      -4      4       6       ]
Decomposing
Deleting matrix
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving if statement
Leaving inner for loop
Leaving outer for loop
Returning 0 from LUDecompose
Deleting matrix
warning: HEAP[test.exe]:
warning: Heap block at 00801188 modified at 00801198 past requested size of 8

Program received signal SIGTRAP, Trace/breakpoint trap.
0x76fdee8b in ?? ()

我已经在网上查找了错误,我怀疑这是关于超出范围的事情,但我没有看到为什么。

请温柔一点,这是我第一次提出这样的问题;)

编辑:清理测试.cpp一点,删除了未使用的行列式和矩阵

编辑2:我知道我需要调试这个程序。问题是我不明白为什么它会崩溃。当我在 gdb 中使用 bt 时,它将我指向 de 析构函数和上面的任何帧,这些帧都与向量 (de) 分配器有关。

编辑 3:删除了 =运算符,将构造函数中 [] 的使用更改为 at() 方法。根据要求,这里是设置方法:

void Matrix::set(int row, int col, double value)
{
    array[row][col] = value;
}
void Matrix::set (Table& t)
{
    if (t.size() > this->getCols())
    {
        this->expand(0,t.size() - this->getCols());
    }
    if (t[0].size() > this->getRows())
    {
        this->expand(t[0].size() - this->getRows(),0);
    }
    for (int i = 0; i < t[0].size(); i++)
    {
        for (int j = 0; j < t.size(); j++)
        {
            this->set(i,j,t[i][j]);
        }
    }
}

编辑4:更新了构造函数以反映Paul McKenzie的评论

编辑5:很抱歉没有首先发布以下功能,我只是觉得我的帖子已经足够长了......无论如何,你去:

void Matrix::operator*= (double d)
{
    for (int i = 0; i < this->getRows(); i++)
    {
        for (int j = 0; j < this->getCols(); j++)
        {
            this->set(i, j, this->get(i,j) * d);
        }
    }
}
void Matrix::operator/= (double d)
{
    if (d != 0)
    {
        for (int i = 0; i < this->getRows(); i++)
        {
            for (int j = 0; j < this->getCols(); j++)
            {
                this->set(i, j, this->get(i,j) / d);
            }
        }
    }
    else
    {
        cout << "Can not divide by zero" << endl;
    }
}
bool Matrix::isSquare () const
{
    if (this->getRows() == this->getCols())
    {
        return true;
    }
    else
    {
        return false;
    }
}
int Matrix::getRows() const
{
    return this->array.at(0).size();
}
int Matrix::getCols() const
{
    return this->array.size();
}
double Matrix::get(int row, int col) const
{
    if ((row < this->getRows()) && (col < this->getCols()))
    {
        return array[row][col];
    }
    else
    {
        cout << "Couldn't get (" << row << "," << col <<"), element is out of bounds. dim = " << this->getRows() << " x " << this->getCols() << endl;
        return -1;
    }
}
int Matrix::getRow (int row, Matrix& dest) const
{
    if (!dest.isRow())
    {
        cout << "Destination matrix is not a row matrix" << endl;
        return -1;
    }
    else
    {
        for (int i = 0; i < this->getCols(); i++)
        {
            dest.set(0, i, this->get(row,i));
        }
        return 0;
    }
}
int Matrix::addRows (int row, const Matrix& rrm)
{
    if (!rrm.isRow())
    {
        cout << "Specified matrix is not a row matrix." << endl;
        return -1;
    }
    else if (rrm.getCols() != this->getCols())
    {
        cout << "Matrix dimensions do not match." << endl;
        return -1;
    }
    else if (row >= this->getRows())
    {
        cout << "Given row number exceeds amount of rows in matrix." << endl;
        return -1;
    }
    else
    {
        for (int i = 0; i < rrm.getCols(); i++)
        {
            this->set(row, i, this->get(row, i) + rrm.get(0,i));
        }
        return 0;
    }
}

编辑6:我通过VS的调试器运行了我的代码,这给了我一个超出范围的异常Matrix::set (int row, int col, double value)。奇怪的是,我已经更新了进行范围检查的方法。调用堆栈如下所示:

矩阵.cpp::set(整数行,整数列,双精度值) @ 行 415 ( array.at(row).at(col) = value;

矩阵.cpp::矩阵(int r, int c) @ line 25 (内部 for 循环的闭合括号)

Matrix

.cpp::LUDecompose(Matrix&refLower, Matrix&refUpper) @ line 526 ( Matrix rowMatrix(1, this->getCols());

测试.cpp::主@35行(cout << "Test.cpp regained control" << endl;

这是该方法当前的样子:

void Matrix::set(int row, int col, double value)
{
    if ((row < this->getRows()) && (col < this->getCols()))
    {
        array.at(row).at(col) = value;
    }
    else
    {
        cout << "Trying to assign to (" << row << "," << col << "): Out of bounds, dim = " << this->getRows() << " x " << this->getCols() << endl;
    }
}

编辑7:在VS中摆弄了一番后,我能够修复代码。我进行了多次编辑,但我很确定导致上述异常的是 array.at(n)返回第n列(而不是第n行,如我的代码所示)和 array.at(n).at(m)返回位置(m,n)的元素(其中m是第m行,n是第n列)感谢大家对我的帮助,这里有一个固定集方法的副本:

void Matrix::set(int row, int col, double value)
{
    if ((row < this->getRows()) && (col < this->getCols()))
    {
        array.at(col).at(row) = value;
    }
    else
    {
        cout << "Trying to assign to (" << row << "," << col << "): Out of bounds, dim = " << this->getRows() << " x " << this->getCols() << endl;
    }
}

调试程序的调试版本时,编译器会在代码中插入额外的运行时检查,这对您不可见。这些检查可以检测您是否释放内存两次、使用未初始化的变量、溢出分配的内存块等。这旨在帮助您的程序正在做一些可能未被发现的非法事情。这些检查在发布版本中不存在,因此永远不会显示错误/警告,但您的程序将随机崩溃和/或行为异常。

在这种情况下,您有以下警告:

警告:00801188处的堆块在超过请求大小 8 时修改00801198

运行时检查检测到您在内存位置 00801188 分配了 8 个字节,并且您从此位置开始一直写入超过 8 个字节,一直到 00801198。

几乎总是指向在循环中使用数组时的问题。下面是一个示例:

假设您分配了 10 个整数的数组:int my[10];现在,您要将一些值写入每个数组成员:

for ( int i=0; i<=10; i++ ) {
  my[i]=some_calculation();
}

这将导致像您这样的确切错误。由于条件是i<=10(程序员不小心,它应该是i<10i<=9),写入的最后一个成员是my[10],第 11 个数组成员,但您只为 10 分配了空间。因此,位于第 10 个成员之后的其他一些内存被覆盖,导致程序中出现不可预测的行为。


最后,检查将值写入数组

成员的所有循环,并确保写入的数组元素数不超过分配的数组元素。

程序崩溃的原因之一是您可能会删除某些内容两次,请检查程序是否在IDE中编译程序