1
I’m writing a class that deals with C++ matrices. However when creating a method to calculate the determinant of a matrix I am bumping into the following error:
double free or corruption (out)
Below, the file with the definitions of class methods:
#include "Matriz.hpp"
#include <iostream>
#include <cassert>
#include <cmath>
//Construtor para uma matriz que não rebece nenhum parametro de entrada. Dessa forma ela aloca memória para uma matriz 3x3, com todos os elementos iguais a zero.
Matriz::Matriz() {
mColunas = 3;
mLinhas = 3;
mData = new double* [mLinhas];
for (int i = 0; i < mColunas; i++)
{
mData[i] = new double [mColunas];
}
}
//Construtor para uma matriz quadrada (NxN), alocando memória para uma matriz de ordem N, tal que N é o número de elementos (n_elementos).
Matriz::Matriz(int n_elementos) {
assert(n_elementos > 0);
mColunas = n_elementos;
mLinhas = n_elementos;
mData = new double* [mLinhas];
for (int i = 0; i < mColunas; i++)
{
mData[i] = new double [mColunas];
}
}
//Construtor que recebe o número de colunas (n_colunas) e o número de linhas (n_linhas) da matriz e aloca memória com base nesses valores.
Matriz::Matriz(int n_linhas, int n_colunas) {
assert(n_linhas > 0 && n_colunas > 0);
mColunas = n_colunas;
mLinhas = n_linhas;
mData = new double* [mLinhas];
for (int i = 0; i < mColunas; i++)
{
mData[i] = new double [mColunas];
}
}
//Sobrescreve o destrutor do objeto, de modo que a memória seja devidamente desalocada;
Matriz::~Matriz() {
for (int i = 0; i < mLinhas; i++)
{
delete[] mData[i];
}
delete[] mData;
}
//Retorna o numero de linhas da matriz
int Matriz::GetNumLinhas() const {
return mLinhas;
}
//Retorna o numero de colunas da matriz
int Matriz::GetNumColunas() const {
return mColunas;
}
//Retorna o determinante de uma determinada matriz quadrada A usando o método de Laplace. Se as a matriz for de ordem 1, o valore retornado será o unico elemento que ela possui.
double Matriz::CalculaDeterminante() {
assert(mLinhas == mColunas);
double determinante, soma;
if (mLinhas == 1) {
determinante = mData[0][0];
}
else {
Matriz MatAux(mLinhas-1, mColunas-1);
soma = 0.0;
for (int coluna = 0; coluna < mColunas; coluna++) {
int iAux = 0;
for (int i = 0; i < mLinhas; i++) {
if (i != 0) {
int jAux = 0;
for (int j = 0; j < mColunas; j++) {
if (j != coluna) {
MatAux.mData[iAux][jAux] = mData[i][j];
jAux++;
}
}
iAux++;
}
}
soma += (-1.0)*pow(-1.0, coluna)*mData[0][coluna]*MatAux.CalculaDeterminante();
}
determinante = soma;
}
return determinante;
}
//Sobrescreve o método de colchetes. Desse forma é possível acessar o ponteiro que armazena a linha no índice dado (index_linha). Como ponteiros já suportam nativamente o operador de conchetes, para acessar um determinado elemento na possivel i,j, sendo i o numero da linha e j o número da coluna, basta escrever A[i][j]. Note que o acesso ao elemento é baseado no 0, ou seja, o index do primeiro elemento será 0, e o índice do ultimo será N-1, tal que N é o número de linhas.
double* Matriz::operator[](int index_linha) {
assert(index_linha > -1);
assert(index_linha < mLinhas);
return mData[index_linha];
}
//Sobrescreve o operador parenteses. Funciona de maneira semelhante ao operador colchetes, mas nesse caso, o indice do primeiro elemento é 1, e do último elemento é N, tal que N é o numero de colunas ou linhas. É utilizado de maneira semelhante a de um função, de forma que o elemento na posição i,j de uma matriz M é dado por M(i,j).
double& Matriz::operator()(int index_linha, int index_coluna) {
assert(index_coluna > 0);
assert(index_coluna < mColunas+1);
return mData[index_linha][index_coluna];
}
//Sobrescreve o operador de atribuição. As informações de uma matriz é passado para outra desde que elas possuam o memso tamanho.
Matriz& Matriz::operator=(const Matriz& outraMatriz) {
assert(mLinhas == outraMatriz.mLinhas);
assert(mColunas == outraMatriz.mColunas);
for (int i = 0; i < mLinhas; i++)
{
for (int j = 0; j < mColunas; j++)
{
mData[i][j] = outraMatriz.mData[i][j];
}
}
}
//Sobrescreve o operador de atribuição junto adição (+=). As informações de duas matrizes A e B são somadas e atribuidas a matriz A, desde que possuam o mesmo tamanho.
Matriz& Matriz::operator+=(const Matriz& outraMatriz) {
assert(mLinhas == outraMatriz.mLinhas);
assert(mColunas == outraMatriz.mColunas);
for (int i = 0; i < mLinhas; i++)
{
for (int j = 0; j < mColunas; j++)
{
mData[i][j] += outraMatriz.mData[i][j];
}
}
}
//Sobrescreve o operador de atribuição junto subtração (-=). As informações de duas matrizes A e B são somadas e atribuidas a matriz A, desde que possuam o mesmo tamanho.
Matriz& Matriz::operator-=(const Matriz& outraMatriz) {
assert(mLinhas == outraMatriz.mLinhas);
assert(mColunas == outraMatriz.mColunas);
for (int i = 0; i < mLinhas; i++)
{
for (int j = 0; j < mColunas; j++)
{
mData[i][j] -= outraMatriz.mData[i][j];
}
}
}
//Sobrescreve o operador de atribuição junto multiplicação (-=). As informações de duas matrizes A e B são multiplicadas e atribuidas a matriz A, desde que possuam o mesmo tamanho.
Matriz& Matriz::operator*=(const Matriz& outraMatriz) {
assert(mColunas == outraMatriz.mLinhas);
double soma;
for (int k = 0; k < outraMatriz.mColunas; k++) {
for (int i = 0; i < mLinhas; i++) {
soma = 0.0;
for (int j = 0; j < mColunas; j++) {
soma += mData[i][j] * outraMatriz.mData[j][k];
}
mData[i][k] = soma;
}
}
}
//Realiza a soma de duas matrizes de mesmo tamanho e retorna uma matriz com mesmo tamanho das anteriores.
Matriz Matriz::operator+(const Matriz& outraMatriz) {
assert(mLinhas == outraMatriz.mLinhas);
assert(mColunas == outraMatriz.mColunas);
Matriz Saida(mLinhas, mColunas);
for (int i = 0; i < mLinhas; i++)
{
for (int j = 0; j < mColunas; j++)
{
Saida[i][j] = mData[i][j] + outraMatriz.mData[i][j];
}
}
return Saida;
}
//Realiza a subtração de duas matrizes de mesmo tamanho e retorna uma matriz com mesmo tamanho das anteriores.
Matriz Matriz::operator-(const Matriz& outraMatriz) {
assert(mLinhas == outraMatriz.mLinhas);
assert(mColunas == outraMatriz.mColunas);
Matriz Saida(mLinhas, mColunas);
for (int i = 0; i < mLinhas; i++)
{
for (int j = 0; j < mColunas; j++)
{
Saida[i][j] = mData[i][j] - outraMatriz.mData[i][j];
}
}
return Saida;
}
//Realiza a multiplicação de um escalar n por uma matrix A e retorna uma matriz de saida com as mesma dimensões da matriz A.
Matriz Matriz::operator*(double n) {
Matriz Saida(mLinhas, mColunas);
for (int i = 0; i < mLinhas; i++)
{
for (int j = 0; j < mColunas; j++)
{
Saida[i][j] = mData[i][j] * n;
}
}
return Saida;
}
//Realiza a multiplição de uma matriz A por uma outra matriz B e retorna uma matriz de saida com o número de linhas da matriz A e de colunas da matriz B. A operação só é realizada se o número de colunas de A for igual ao número de colunas de B.
Matriz Matriz::operator*(const Matriz& outraMatriz) {
assert(mColunas == outraMatriz.mLinhas);
Matriz Saida(mLinhas, outraMatriz.mColunas);
double soma;
for (int k = 0; k < outraMatriz.mColunas; k++) {
for (int i = 0; i < mLinhas; i++) {
soma = 0.0;
for (int j = 0; j < mColunas; j++) {
soma += mData[i][j] * outraMatriz.mData[j][k];
}
Saida[i][k] = soma;
}
}
return Saida;
}
//Sobrescreve o operador << para retornar na tela as informações contidas e, uma matriz A.
std::ostream& operator<<(std::ostream& saida, const Matriz& A) {
for (int i = 0; i < A.mLinhas; i++)
{
for (int j = 0; j < A.mColunas; j++)
{
saida << A.mData[i][j] << "\t";
}
saida << std::endl;
}
}
I wrote the following file to test the method CalculaDeterminante()
:
#include "Matriz.hpp"
#include <iostream>
int main(int argc, char const *argv[])
{
Matriz C(3,3);
for (int i = 0; i < C.GetNumLinhas(); i++)
{
for (int j = 0; j < C.GetNumColunas(); j++)
{
if (i%2 == 0) {
C[i][j] = i+j+8;
} else {
C[i][j] = i+j*3;
}
}
}
std::cout << C << std::endl;
std::cout << std::endl;
std::cout << C.CalculaDeterminante() << std::endl;
return 0;
}
The function even returns the correct value at the end of the calculations, but I would like to better understand why the error message.
Edit #1
Below the header file Matriz.hpp
#pragma once
#include <iostream>
class Matriz {
private:
double** mData;
int mColunas;
int mLinhas;
public:
Matriz();
Matriz(int n_elementos);
Matriz(int n_linhas, int n_colunas);
~Matriz();
int GetNumLinhas() const;
int GetNumColunas() const;
double CalculaDeterminante();
double* operator[](int index_linha);
double& operator()(int index_linha, int index_coluna);
Matriz& operator=(const Matriz& outraMatriz);
Matriz& operator+=(const Matriz& outraMatriz);
Matriz& operator-=(const Matriz& outraMatriz);
Matriz& operator*=(const Matriz& outraMatriz);
Matriz operator+(const Matriz& outraMatriz);
Matriz operator-(const Matriz& outraMatriz);
Matriz operator*(double n);
Matriz operator*(const Matriz& outraMatriz);
friend std::ostream& operator<<(std::ostream& saida, const Matriz& A);
};
Edit #2 In fact, when running the test file as previously written, the problem does not appear. But when I create and destroy a new matrix above the C Matrix declaration, as shown in the code below, that’s when the problem happens.
#include "Matriz.hpp"
#include <iostream>
int main(int argc, char const *argv[])
{
Matriz C(3,3);
for (int i = 0; i < C.GetNumLinhas(); i++)
{
for (int j = 0; j < C.GetNumColunas(); j++)
{
if (i%2 == 0) {
C[i][j] = i+j+8;
} else {
C[i][j] = i+j*3;
}
}
}
std::cout << C << std::endl;
std::cout << std::endl;
std::cout << C.CalculaDeterminante() << std::endl;
return 0;
}
The error means you are doing a free duplicate, and it is easy to analyze with a tool like Valgrind. If you put the Matrix.hpp header that is missing in the question it is even easier to run the code and tell where the problem is.
– Isac
I added the file. I’ll take a look at this Valgrind too. Thank you very much!
– João Carvalho