C ++ 2D arrays of object constructor

In my Dev C ++, I am trying to create a 2D Array class that acts like a Grid. But one problem is that I'm not sure what to do for the constructor.

When I try to compile, I get the following errors: In the constructor "Grid :: Grid (int, int)": "sqaures" is not a type 'yPos' cannot appear in constant expression [Assembly error] [grid.o] Error 1

Here is the header file:

#ifndef GRID_H
#define GRID_H

using namespace std;

class Grid
{
      public:

      Grid(int xPos, int yPos);
      // Constructor
      // POST: Creates the squares of grid; (x,y) coordinates

      private:

      int squares;
      //2D Array
      //the squares; (x,y) coordinates of the grids      
};

#endif

      

And heres.cpp file for grid.h functions

#include <iostream>
#include "grid.h"

using namespace std;

Grid::Grid(int xPos, int yPos)
{
    squares = new squares[xPos][yPos];
    //Trying to make squares into a 2D array, and turn the values into the arguments
    //into the the x,y coordinates 
}

      

My constructor on .cpp files doesn't work and I'm not sure what to do. Anyone have any solutions?

+1


source to share


7 replies


There are several problems with your code. First of all, your member variable "squares" must be a pointer to an int , not an int:

int *squares;

      

Then the following line will give an error:

squares = new squares[xPos][yPos];

      

What you really need is a block of memory for a 2D array:

squares = new squares[xPos * yPos];

      

Also, you must store the dimensions of this array in member variables (eg "sizeX" and "sizeY")



You now have a block of memory that will contain a 2D array of squares. I usually overload the () operator to access an element in this array:

int &Grid::operator() (int x, int y)
{
      // you can check array boundaries here
      return squares[y + sizeX*x];
}

      

If you have problems with the operator stuff, just create a member function:

int Grid::get(int x, int y)
{
     // check array bounds
     return squares[y + sizeX*x];
}
void Grid::set(int x, int y, int value)
{
     // check array bounds
     squares[y + sizeX*x] = value;
}

      

Finally, you need a destructor to free memory:

Grid::~Grid()
{
     delete [] squares;
}

      

This is how I like it ("C-c-classes" style). In another answer, David Norman gives a nice "Standard C ++" way to implement your class.

+4


source


Not directly relevant to your question, but you shouldn't use declarations in your header files (.h / .hpp).

eg:

using namespace std;
      



They refer to cpp files.

See Herb Sutters GOTW (Guru of the Week) # 53 for reasons.

+3


source


To avoid memory problems, use a vector of vectors.

In the title

class Grid
{
    ...
    std::vector< std::vector<squares> > squares;
    ...
}

      

In .cpp

Grid::Grid(int xPos, int yPos)
{
    squares.resize(xPos);
    for (int i = 0; i < xPos; i++) {
        squares[i].resize(yPos);
    }
}

      

Later:

squares[2][3] = square(...);

      

Or use a vector of a vector of smart pointers if you want new squares.

+2


source


Are you sure you received the code? Are your squares defined as int and not as int **? I'm not sure how you compile this ....

EDIT: The error message you get is that you are defining squares as int. Hence, it can only accept one integer. Your constructor is trying to assign an entire array to it. Are you familiar enough with pointers, arrays, dereferencing and all that? A two-dimensional array is usually complex.

If you are good at writing your 2D array, you can only use one array and just map the two dimensional addresses into one index.

+1


source


Grid::Grid(int xPos, int yPos) {
    squares = new squares[xPos][yPos];
    //Trying to make squares into a 2D array, and turn the values into the arguments
    //into the the x,y coordinates 
}

      

This is, of course, wrong. you need to do new int[xPos][yPos]

. The operator requires you to give it a type. But still you are not finished. yPos

must be known at compile time. This is not the case in your example. The reason is that it becomes part of the type returned by the new expression:

int (*squares)[yPos] = new int[xPos][yPos];

      

Since the types are static, yPos cannot be determined at runtime. What you really want is an int vector. But I believe that you want to manage memory yourself because you want to learn the language rules. So go with this:

  • Make squares int*

    :int *squares;

  • Change the line in the constructor to squares = new int[xPos * yPos];

  • Add a line like this to your destructor delete[] squares;

    .
  • Add a copy constructor and a copy operator that copies your memory when you copy your instance.
  • add a member function as shown below:

code:

int & get(int x, int y) { return squares[y * yPos + x]; }

      

Which will give you an integer at a given position. You can of course also overload operator[]

to have natural access using 2d indices:

class Grid {
    struct proxy {
        proxy(int *row):row(row) { }
        int & operator[](int x) {
            return row[x];
        }
        int * row;
    };

    int * squares;
public:
    proxy operator[](int y) {
        return proxy(squares + yPos * y); 
    }
};

      

The outer index will select the row, the inner will select the column. If you need to manage your memory properly, you can move on to better solutions. boost::multi_array

Ideal for your task : Boost.MultiArray

Other problems

Never do using namespace std;

in a header file. The reason is that all code that indirectly or directly includes this file also automatically includes this line and therefore sees all std ::. Name collisions occur as soon as the code tries to reference names, which are also defined by the C ++ standard library.

+1


source


This does not work:

squares = new squares[xPos][yPos];

      

You need:

squares = new (int*)[xPos];
for (int x = 0; x < xPos; ++x) {
     squares[x] = new int[yPos];
}

      

And personally, this is the wrong way to do it. I prefer

class Grid {

     class Row {
         int* row; // this is a pointer into Grid::grid
         int size; // this equals Grid::col_count and is only here for bounds checking
     public:
         Row(int s, int* r) : size(s), row(r) {}

         int& operator[](int col) {
             if (col >=0 && col < size) return row[col];
             throw OutOfBoundsException();
         }
     };

     int row_count, col_count;
     int* grid;
     Row* rows;

  public:
     Grid(int x, int y) : row_count(x), col_count(y) {
         rows = new (Row*)[row_count];
         grid = new int[row_count*col_count];
         int* grid_walk = grid;
         for (int i = 0; i < row_count; ++i) {
             rows[i] = new Row(col_count, grid_walk);
             grid_walk += col_count;
         }
     }
     ~Grid() { delete[] rows; delete[] grid; }

     Row& operator[](int row) {
         if (row ?= 0 && row < row_count) return rows[row];
         throw OutOfBoundsException();
     }

     int rows() const { return row_count; }
     int cols() const { return col_count; }

};

Grid checkers(8,8);

for (r = 0; r < checkers.row_count(); ++r) {
    for (c = 0; c < checkers.col_count(); ++c) {
        if ((r + c) % 2 == 1) checkers[r][c] = -1; // red space
        else if (r < 3) checkers[r][c] = 1; // player 1
        else if (r >= 5) checkers[r][c] = 2; // player 2
        else checkers[r][c] = 0; // open square
    }
}
// etc.

      

Hopefully not too many typos.

+1


source


According to David Norman replies , use std::vector

. However, there is a bug in his answer, the vector must be declared like this:

class Grid
{
...

    std::vector< std::vector<int> > squares;
};

      

You can also initialize it with a vector constructor that takes a size and a value:

Grid::Grid(int xPos, int yPos)
:   squares( xPos, std::vector<int>( yPos, 0 ) )
{
}

      

+1


source







All Articles