MAtrix 乘法中的分段错误

Segmentation Fault in MAtrix Multiplication

本文关键字:分段 错误 MAtrix      更新时间:2023-10-16

我几乎是C/C++的初学者。我试图实现一个程序来使用矩阵幂返回第 n 个斐波那契数的值。我编写了以下代码:

#include <cmath>
#include <iostream>
using namespace std;
typedef struct Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;
}Matrix;
Matrix* init_matrix(unsigned long long n);
Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11);
Matrix* mult_matrix(Matrix* A, Matrix* B);      
Matrix* expo_matrix(Matrix* A,unsigned int n);
unsigned long long fib_matrix_expo(unsigned int n); 
int main() {
    unsigned int n;
    cin >> n;
    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}

Matrix* init_matrix(unsigned long long n) {
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));
    (ret_matrix->a_00) = n;
    (ret_matrix->a_01) = n;
    (ret_matrix->a_10) = n;
    (ret_matrix->a_11) = n;
    return ret_matrix;
}
Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11) {
/*==================================================================================*/
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));
    (ret_matrix->a_00) = a_00;
    (ret_matrix->a_01) = a_01;
    (ret_matrix->a_10) = a_10;
    (ret_matrix->a_11) = a_11;
    return ret_matrix;  
}

Matrix* matrix_mult(Matrix* A, Matrix* B) {
    Matrix* result = (Matrix*)::operator new (sizeof(Matrix));
    (result->a_00) = ((A->a_00) * (B->a_00) + (A->a_01)*(B->a_10));
    (result->a_01) = ((A->a_00) * (B->a_01) + (A->a_01)*(B->a_11));
    (result->a_10) = ((A->a_10) * (B->a_00) + (A->a_11)*(B->a_10));
    (result->a_11) = ((A->a_10) * (B->a_01) + (A->a_11)*(B->a_11));
    return result;
}
Matrix* matrix_expo(Matrix* base_matrix, unsigned int index) {
    Matrix* result;
    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix* temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult( matrix_expo(temp,2), matrix_expo(base_matrix,(index % 2)) );
    }
    return result;
}
unsigned long long fib_matrix_expo(unsigned int n) {
    unsigned long long result = 0;
    Matrix* base = init_matrix(1,1,1,0);
    if (n == 0) {
        result = 0;
    }
    else {
        base = matrix_expo(base,(n-1));
        result = (base->a_00);
    }
    return result;      
}

但是此代码会导致值>= 3 的分段错误。我觉得问题出在 mult_matrix(( 函数上,但我找不到它。请帮忙。

编辑:已找到导致溢出的错误,但此处似乎还存在其他逻辑错误。特别是编辑后的代码输出错误的值,并且输出到连续输入(如 1 和 2、3 和 4、5 和 6(是相同的。:(

编辑后的代码:

#include <cmath>
#include <iostream>
using namespace std;
typedef struct Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;
}Matrix;
Matrix* init_matrix(unsigned long long n);
Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11);
Matrix* mult_matrix(Matrix* A, Matrix* B);      
Matrix* expo_matrix(Matrix* A,unsigned int n);
unsigned long long fib_matrix_expo(unsigned int n); 
int main() {
    unsigned int n;
    cin >> n;
    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}

Matrix* init_matrix(unsigned long long n) {
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));
    (ret_matrix->a_00) = n;
    (ret_matrix->a_01) = n;
    (ret_matrix->a_10) = n;
    (ret_matrix->a_11) = n;
    return ret_matrix;
}
Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11) {
/*==================================================================================*/
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));
    (ret_matrix->a_00) = a_00;
    (ret_matrix->a_01) = a_01;
    (ret_matrix->a_10) = a_10;
    (ret_matrix->a_11) = a_11;
    return ret_matrix;  
}

Matrix* matrix_mult(Matrix* A, Matrix* B) {
    Matrix* result = (Matrix*)::operator new (sizeof(Matrix));
    (result->a_00) = ((A->a_00) * (B->a_00) + (A->a_01)*(B->a_10));
    (result->a_01) = ((A->a_00) * (B->a_01) + (A->a_01)*(B->a_11));
    (result->a_10) = ((A->a_10) * (B->a_00) + (A->a_11)*(B->a_10));
    (result->a_11) = ((A->a_10) * (B->a_01) + (A->a_11)*(B->a_11));
    return result;
}
Matrix* matrix_expo(Matrix* base_matrix, unsigned int index) {
    Matrix* result;
    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix* temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult(temp,temp);
        result = matrix_mult(result,matrix_expo(base_matrix,(index % 2)));
    }
    return result;
}
unsigned long long fib_matrix_expo(unsigned int n) {
    unsigned long long result = 0;
    Matrix* base = init_matrix(1,1,1,0);
    if (n == 0) {
        result = 0;
    }
    else {
        base = matrix_expo(base,(n-1));
        result = (base->a_00);
    }
    return result;      
}

编辑:此错误也已解决。但正如保罗所指出的,这有很多记忆泄漏。我将尝试在不使用手动动态内存分配的情况下实现这一点并重新发布它。然后按照 n.m 的建议。我将在使用构造函数并删除其他不必要的复杂功能后更新代码。当前工作代码:

编辑:没有内存泄漏的代码:

#include <cmath>
#include <iostream>
using namespace std;
struct Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;
};
Matrix init_matrix(unsigned long long n);
Matrix init_matrix(unsigned long long a_00, unsigned long long a_01,
                   unsigned long long a_10, unsigned long long a_11);
Matrix mult_matrix(const Matrix& A, const Matrix& B);      
Matrix expo_matrix(const Matrix& A,unsigned int n);
unsigned long long fib_matrix_expo(unsigned int n); 
int main() {
    unsigned int n;
    cin >> n;
    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}

Matrix init_matrix(unsigned long long n) {
    Matrix ret_matrix;
    ret_matrix.a_00 = n;
    ret_matrix.a_01 = n;
    ret_matrix.a_10 = n;
    ret_matrix.a_11 = n;
    return ret_matrix;
}
Matrix init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11) {
/*==================================================================================*/
    Matrix ret_matrix;
    ret_matrix.a_00 = a_00;
    ret_matrix.a_01 = a_01;
    ret_matrix.a_10 = a_10;
    ret_matrix.a_11 = a_11;
    return ret_matrix;  
}

Matrix matrix_mult(const Matrix& A, const Matrix& B) {
    Matrix result;
    result.a_00 = ((A.a_00) * (B.a_00) + (A.a_01)*(B.a_10));
    result.a_01 = ((A.a_00) * (B.a_01) + (A.a_01)*(B.a_11));
    result.a_10 = ((A.a_10) * (B.a_00) + (A.a_11)*(B.a_10));
    result.a_11 = ((A.a_10) * (B.a_01) + (A.a_11)*(B.a_11));
    return result;
}
Matrix matrix_expo(const Matrix& base_matrix, unsigned int index) {
    Matrix result;
    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult(temp,temp);
        if(index % 2 == 1) {
            result = matrix_mult(result,base_matrix);
        }
    }
    return result;
}
unsigned long long fib_matrix_expo(unsigned int n) {
    unsigned long long result = 0;
    Matrix base = init_matrix(1,1,1,0);
    if (n == 0) {
        result = 0;
    }
    else {
        base = matrix_expo(base,(n-1));
        result = base.a_00;
    }
    return result;      
}

由于这里的递归,您在matrix_expo函数中存在堆栈溢出

Matrix* temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
result = matrix_mult( matrix_expo(temp,2), matrix_expo(base_matrix,(index % 2)) );

让我们看看为什么

Matrix matrix_expo(Matrix base_matrix, unsigned int index) {
    Matrix result;
    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult( matrix_expo(temp,2), matrix_expo(base_matrix,(index % 2)) );
    }
    return result;
}

如果index == 2则始终达到matrix_expo(temp, 2),这会导致无限递归。

其他一些问题是new和从不使用delete,这里实际上失去了delete的机会

base = matrix_expo(base,(n-1));

因为可以使用new分配base并且您重新确定指向new分配内存的基本指针。

我说可以使用new

分配,因为这行
result = base_matrix;

在这里,如果出现前面提到的情况,您将返回base它自己,但在任何其他情况下,此函数中要result的其他赋值将使用new分配,这将返回指向最初分配的内存的指针,因此,如果您使用 delete 运算符释放此内存, 你有机会加倍免费。

这是一个使用进行Matrix的C++实现。不幸的是,我对矩阵的了解不足以指出原始代码的"问题"问题;简单地用类重写它似乎已经摆脱了这个问题。我无法解释您的expo函数内部工作原理,所以我将其编写为一个简单的循环。

使用类意味着所有操作都只"在"单个矩阵上;不再需要制作多个副本!(expo函数中的1,1,1,0助手除外;C++将自动删除该函数末尾的temp1矩阵。

默认情况下,一个新的矩阵会用 1,1,1,0 初始化,因此可以删除 expofib_matrix_expo中的init

这也意味着您可以轻松扩展 Matrix 类以执行其他功能。

#include <cmath>
#include <iostream>
using namespace std;
class Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;
public:
    Matrix();
    void init(unsigned long long n);
    void mult(Matrix* B);
    void expo (unsigned int n);
    unsigned long long value ()
    {
        return a_00;
    }
};
unsigned long long fib_matrix_expo(unsigned int n); 
int main() {
    unsigned int n;
    cin >> n;
    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}
/* In this, and all other class functions, the specifier 'this->' is
   not required. Per definition, all variables from the class are
   immediately accessible. However, including 'this->..' makes it
   clear you *are* modifying the class variables, and not local ones
   with the same name */
Matrix::Matrix () {
    this->a_00 = 1;
    this->a_01 = 1;
    this->a_10 = 1;
    this->a_11 = 0;
}

void Matrix::init (unsigned long long n) {
    this->a_00 = n;
    this->a_01 = n;
    this->a_10 = n;
    this->a_11 = n;
}
void Matrix::mult(Matrix* B)
{
    unsigned long long t00,t01,t10,t11;
    t00 = this->a_00 * B->a_00 + this->a_01 * B->a_10;
    t01 = this->a_00 * B->a_01 + this->a_01 * B->a_11;
    t10 = this->a_10 * B->a_00 + this->a_11 * B->a_10;
    t11 = this->a_10 * B->a_01 + this->a_11 * B->a_11;
    this->a_00 = t00;
    this->a_01 = t01;
    this->a_10 = t10;
    this->a_11 = t11;
    // printf ("%llu %llu %llu %llun", a_00, a_01, a_10, a_11);
}
void Matrix::expo(unsigned int index)
{
    if (index == 0)
    {
        this->init(1);
        return;
    }
    if (index == 1)
    {
        return;
    }
    Matrix temp1;
    // temp1 will initialize itself with (1,1,1,0),
    // nothing more needed
    while (--index > 0)
    {
        this->mult (&temp1);
    }
}
unsigned long long fib_matrix_expo (unsigned int n)
{
    Matrix base;
    if (n == 0)
        return 0;
    // No need to initialize to the default values, as this
    // is done in the default constructor.
    base.expo(n-1);
    return base.value();
    // Since 'base' is a locally created class object, you
    // do not need to delete it.
}

欢迎建设性的批评,因为我不是一个日常C++程序员;)