Jorge Vega Sánchez
Jorge Vega Sánchez

Reputation: 7590

Memory allocation to define a matrix structure

I'm programming A* code and have a weird 'Segmentation Fault' problem trying to access to a int** matrix.

Here the code of an example of matrix. When i try t plot the first cout i obtained a segmentation fault 11.

#include <iostream>

using namespace std;

int main(int argc, char** argv)
{
    int** matriz;

    matriz = (int**) malloc(10 * sizeof(int));

    // Defino una matriz de 10x12
    for (int i=0; i<10; i++)
    {
        matriz[i] = (int*) malloc(12 * sizeof(int));

        for (int j=0; j < 12; j++)
        {
            if( i == 11 && j == 5)
                matriz[i][j] = 13;
            else if( i == 10 && j == 7)
                matriz[i][j] = 5;
            else if( i == 3 && j == 11)
                matriz[i][j] = 4;
            else
                matriz[i][j] = 0;
        }
    }

    // Imprimo valores de prueba para comprobar que todos son accesible y que no encuentro un 'Segmentation Fault'
    cout << "Valor en (11, 5) --> " << matriz[11][5] << endl;
    cout << "Valor en (10, 7) --> " << matriz[10][7] << endl;
    cout << "Valor normal 0 en (4, 4) --> " << matriz[4][4] << endl;
    cout << "Valor en (3, 11) --> " << matriz[3][11] << endl;

    return 0;
}

Someone could tell what i'm doing wrong. I can't understand why i can plot the value of coordinates for example (4,4) and (3,11) but no those (11, 5) or (10,7) which are nears the boders of the matrix.

Thanks in advance.

Upvotes: 0

Views: 153

Answers (2)

Pixelchemist
Pixelchemist

Reputation: 24946

First of all you can read Why pointer to pointer and vector of vector is bad for simple matrices. You'll need to enter password "p2pbad" (without "").

This line

cout << "Valor en (11, 5) --> " << matriz[11][5] << endl;

will try to access an element which is not present since your matrix has only 10 rows but you want to get data from row 11 -> segmentation fault. For the same reason the condition

if( i == 11 && j == 5)

does not make sense. i will never be 11, nor will i == 10 in the next condition ever be true since i<10.

Writing really nice code for universal matrix handling is a huge task but you could probably write a simple/basic, templated matrix class with some effort.

A basic example using std::allocator would be like

template <typename _T>
class basic_matrix
{
public:
  typedef basic_matrix<_T>                this_type;
  typedef ::std::allocator<_T>            alloc;
  typedef typename alloc::value_type      value;
  typedef typename alloc::pointer         ptr;
  typedef typename alloc::const_pointer   const_ptr;
  typedef typename alloc::reference       ref;
  typedef typename alloc::const_reference const_ref;
  typedef typename alloc::size_type       size;
  typedef typename alloc::difference_type diff;
  typedef _T&&                            r_ref;

  basic_matrix (void) 
    : _data(nullptr), _x(0U), _y(0U)
  {
  }

  basic_matrix (size const & x, size const & y) 
    : _data(nullptr), _x(0U), _y(0U)
  {
    resize(x,y);
  }

  ~basic_matrix (void)
  {
    if (!empty()) clear();
  }

  void resize (size const &x, size const &y)
  {
    if (x == 0 && y == 0)
    {
      clear();
    }
    else
    {
      ptr new_location = _Allocate(x*y);
      if (!empty())
      { // old data existent -> copy it
        try 
        {
          size const N = min(x, _x), M = min(y, _y);
          for (size i=0; i<N; ++i)
          {
            for (size j=0; j<M; ++j)
            {
              *(new_location + i*y + j) = *(_data + i*_y + j);
            }
          }
        }
        catch (...)
        {
          _Deallocate(new_location, x*y);
          clear();
          throw;
        }
      }
      _data = new_location;
      _x = x;
      _y = y;
    }
  }

  ref operator() (size const &x, size const &y)
  {
    if (x >= _x || y >= _y) throw std::exception("OUT OF RANGE");
    return *(_data + x*_y + y);
  }

  const_ref operator() (size const &x, size const &y) const
  {
    if (x >= _x || y >= _y) throw std::exception("OUT OF RANGE");
    return *(_data + x*_y + y);
  }

  bool empty (void) const
  {
    return (_data == nullptr);
  }

  void clear (void)
  {
    _Deallocate(_data, _x*_y);
    _data = nullptr;
    _x = 0U;
    _y = 0U;
  }

protected:

  ptr _data;
  size _x, _y;
  alloc _allocator;

  ptr _Allocate (size const &num)
  {
    ptr new_location;
    try 
    {
      new_location = _allocator.allocate(num);
    }
    catch (...)
    {
      clear();
      throw;
    }
    return new_location;
  }

  void _Deallocate (ptr location, size const &num)
  {
    _allocator.deallocate(location, num);
  }

};

You will be required to add a copy constructor and an assignment operator and some other stuff ... whatever you want your matrix interface to behave like...

This works using code like this:

int main (void)
{

  basic_matrix<int> matriz(10, 12);

    // Defino una matriz de 10x12
    for (int i=0; i<10; i++)
    {
        for (int j=0; j < 12; j++)
        {
            if( i == 9 && j == 7)
                matriz(i,j) = 5;
            else if( i == 3 && j == 11)
                matriz(i,j) = 4;
            else
                matriz(i,j) = 0;
        }
    }
    cout << "Valor en (10, 7) --> " << matriz(9,7) << endl;
    cout << "Valor normal 0 en (4, 4) --> " << matriz(4,4) << endl;
    cout << "Valor en (3, 11) --> " << matriz(3,11) << endl;
    return 0;
}

It prints:

Valor en (10, 7) --> 5
Valor normal 0 en (4, 4) --> 0
Valor en (3, 11) --> 4

Upvotes: 3

If you use C++ (or better yet C++11, e.g. with a recent GCC -4.7 or better- compiler with g++ -std=gnu++11 -Wall ), you could use std::array (or std::vector at least).

And you should at least code

  matriz = (int**) malloc(10 * sizeof(int*));
  if (!matriz) { perror("malloc matriz"); exit(EXIT_FAILURE); };

(on my Linux/Debian/x86-64 machine, sizeof(int) is 4, but sizeof(int*) is 8)

because each individual element of matriz, e.g. matriz[3] is a pointer.

I would rather suggest using std::array in C++11, and coding

  auto matriz = new std::array<std::array<int,12>,10>();

and #include <array>

Upvotes: 2

Related Questions