Matrix as an attribute?

4

I am trying to create a board, with different dimensions, that is, 3 x 3, 4 x 4 and 5 x 5

The problem is that I do not know if the part of the attributes of my board class is well declared. Can you tell me if it's okay? On the other hand, I was thinking about using a constructor to determine the size of my board, that is, pass parameters to it and create a matrix, but when I initialize it, there is data where it should not be. Do you know where the problem is or am I doing everything wrong?

This is the code of the board class:

    #ifndef TABLERO_H
    #define TABLERO_H

    const int row = 1;
    const int col = 1;

class Tablero
{

    private: 
    int c;
    int f;
    int mat [col][row];

    public:
    Tablero ();
    Tablero (int pC, int pF);
    void mostrarT ();
    void setN (int pA, int pB, int pC, int pD);
    ~Tablero (); 
};


    Tablero::Tablero ()
{
    c = 5;
    f = 4;

    for (int i = 0; i < c; i ++ )
        for (int j = 0; j < f; j ++)
            mat [i][j] = 0;

    mat [3][1] = 1;

}

The implementation is as follows:

Tablero::Tablero(int pC, int pF)
{
    c = pC;
    f = pF;

    for (int i = 0; i < c; i ++ )
        for (int j = 0; j < f; j ++)
            mat [i][j] = 0;

    mat [3][1] = 2;


}

Tablero::~Tablero()
{

}


void Tablero::mostrarT ()
{
    cout << "---------------------------" << endl;

    for (int i = 0; i < c; i++){
        for (int j = 0; j < f; j++){
            cout << mat [i] [j] << "  ";
           }
        cout << endl;
        }


 } 

 void Tablero::setN (int pA, int pB, int pC, int pD)
 {  
    int r;

    r = rand () % (c-1);

    cout  << r << "<<<" << endl;

    while (r == 0 || r == 2 || r == 3 || r == 5 || r == 6 || r == 8)
    {
        r = 0 + rand () % (c-1);
        cout << r << "<<<";
    }

    cout  << r << "<<<" << endl;

    cout << pA << "<<---";

 }

and the main

int main() {
srand (time (NULL));

/*Ficha x;
x.mostrar();
Ficha y;
y.mostrar();*/

Tablero w;
w.mostrarT();

Tablero a (5, 4);
a.mostrarT();
}
    
asked by Cristhian Ivan 15.10.2018 в 02:24
source

2 answers

5

When you use formations 1 , the size must be known at compile time or you must use dynamic memory; so your approach is not valid.

A possible solution for using a constructor to determine the size of the board is, as I mentioned, using dynamic memory, for this your Tablero::mat should be a double pointer:

class Tablero
{
    int columnas;
    int filas;
    int **matriz;

public:
    Tablero ();
    Tablero (int pColumnas, int pFilas);
    void mostrarT ();
    void setN (int pA, int pB, int pC, int pD);
    ~Tablero (); 
};

Tablero::Tablero (int pColumnas, int pFilas) :
    columnas{pColumnas},
    filas{pFilas}
{
    matriz = new int*[pFilas];
    for (int indice = 0; indice < pFilas; ++indice)
        matriz[indice] = new int[pColumnas]{};
}

In the previous proposal I made the following changes:

  • Eliminated the private tag in the class, redundant: The default visibility of the classes is already private.
  • Assigned self-explanatory names to the variables: The names of a single letter do not explain anything of the objective nor function of the variables; the name of a variable should allow you to know at a glance its purpose, making the code less prone to errors and making it easier to read and understand, which any person who works with you (including your future self) will be very grateful.
  • Member Tablero::matriz has become a pointer to pointer to integer, allowing the creation of a bidimensional matrix at runtime. When adding the empty keys when creating the rows ( new int[pColumnas]{} ), the compiler will initialize all the elements to 0.
  • Member variables Tablero:columnas and Tablero:filas are initialized in the initialization list of the constructor, not in the body.
  • This proposal meets your objectives, but it is not practical; there is no guarantee that the rows are attached to memory, which can give performance problems. You could create the matrix as a one-dimensional array and treat it as two-dimensional:

    class Tablero
    {
        int columnas;
        int filas;
        int *matriz;
    
    public:
        Tablero ();
        Tablero (int pColumnas, int pFilas);
        void mostrarT ();
        void setN (int pA, int pB, int pC, int pD);
        ~Tablero (); 
    };
    
    Tablero::Tablero (int pColumnas, int pFilas) :
        columnas{pColumnas},
        filas{pFilas}
    {
        matriz = new int[pColumnas * pFilas]{};
    }
    

    With the previous proposal, assigning a value to row y in column x , would be done as follows:

    matriz[(y * columnas) + x] = valor;
    

    And to get the value of the row y in the column x would be done as follows:

    valor = matriz[(y * filas) + x];
    

    You can forget about memory management and get the same results as the previous proposal if you change Tablero::matriz for std::vector :

    class Tablero
    {
        int columnas;
        int filas;
        std::vector<int> matriz;
    
    public:
        Tablero ();
        Tablero (int pColumnas, int pFilas);
        void mostrarT ();
        void setN (int pA, int pB, int pC, int pD);
        ~Tablero (); 
    };
    
    Tablero::Tablero (int pColumnas, int pFilas) :
        columnas{pColumnas},
        filas{pFilas},
        matriz(pColumnas * pFilas, 0)
    {
    }
    
  • Also known as arrays or in English arrays .
  • answered by 15.10.2018 / 10:00
    source
    4
      

    Can you tell me if it's okay?

    Since you mention that it gives you problems, the answer is obvious, no, it's not right.

      

    Do you know where the problem is or am I doing everything wrong?

    If you want the board to have a dynamic size (that is, you can change from one execution to another), you need to use dynamic memory ... and you are using an array of fixed size. The problem is not that the array is of fixed size, but also has a 1x1 dimension. That is, any board defined by the user will have a larger size and that causes problems.

    I explain. In C ++ there are no checks to verify if you try to access an item that does not belong to your memory. To do those checks, in some cases, the Operating System is in charge and you would not like it to come into action because what you usually do is kill your application so that it does not corrupt the memory.

    So what you have to do is use dynamic memory and at this point you have to make a decision about the default constructor:

    • You eliminate it, since your thing is to know what size the board is going to have. This option is the simplest
    • You prepare the whole class to detect that the board is not initialized.

    Imagine that we chose the first option, the code could look like this:

    class Tablero
    {
    private: 
      int c;
      int f;
      int* mat;
    
    public:
      Tablero (int pC, int pF);
      ~Tablero ();
    
      void mostrarT() const;
      int Get(int pC, int pF) const;
    };
    
    Tablero::Tablero(int pC, int pF)
      : c(pC),
        f(pF),
        mat(new int[Pc*Pf](0))
    {
      std::fill_n(mat,c*f,0); 
    }
    
    Tablero::~Tablero()
    {
      delete mat;
    }
    
    int Get(int pC, int pF) const
    {
      return mat[pF*c+pC];
    }
    
    void Tablero::mostrarT() const
    {
      cout << "---------------------------" << endl;
    
      for (int i = 0; i < f; i++)
      {
        for (int j = 0; j < c; j++)
          cout << Get(i,j) << "  ";
        cout << '\n';
      }
    }
    
        
    answered by 15.10.2018 в 09:58