Is there some way to delay defining the size of an array until a class method or constructor?
What I'm thinking of might look something like this, which (of course) doesn't work:
class Test
{
private:
int _array[][];
public:
Test::Test(int width, int height);
};
Test::Test(int width, int height)
{
_array[width][height];
}
What Daniel is talking about is that you will need to allocate memory for your array dynamically when your Test (width, height) method is called.
You would declare your two dimensional like this (assuming array of integers):
int ** _array;
And then in your Test method you would need to first allocate the array of pointers, and then for each pointer allocate an array of integers:
_array = new *int [height];
for (int i = 0; i < height; i++)
{
_array [i] = new int[width];
}
And then when the object is released you will need to explicit delete the memory you allocated.
for (int i = 0; i < height; i++)
{
delete [] _array[i];
_array [i] = NULL;
}
delete [] _array;
_array = NULL;
vector is your best friend
class Test
{
private:
vector<vector<int> > _array;
public:
Test(int width, int height) :
_array(width,vector<int>(height,0))
{
}
};
I think it is time for you to look up the new/delete operators.
Seeing as this is a multidimensional array, you're going to have to loop through calling 'new' as you go (and again not to forget: delete).
Although I am sure many will suggest to use a one-dimensional array with width*height elements.
(Months later) one can use templates, like this:
// array2.c
// http://www.boost.org/doc/libs/1_39_0/libs/multi_array/doc/user.html
// is professional, this just shows the principle
#include <assert.h>
template<int M, int N>
class Array2 {
public:
int a[M][N]; // vla, var-len array, on the stack -- works in gcc, C99, but not all
int* operator[] ( int j )
{
assert( 0 <= j && j < M );
return a[j];
}
};
int main( int argc, char* argv[] )
{
Array2<10, 20> a;
for( int j = 0; j < 10; j ++ )
for( int k = 0; k < 20; k ++ )
a[j][k] = 0;
int* failassert = a[10];
}
Related
I'm designing a dynamic hurtbox for characters in a text-based game, which catches the locations of hits (or misses) of a weapon swung at them. The location (indices) and damage (magnitude) of hits are then translated into decreases in corresponding limb health variables for a character. My thoughts are that this hurtbox would best be implemented using a class with some 3D vector/array member.
Naturally, I might want varying dimensions of the 3D container for different sizes of enemy, but I'm aware that size is usually determined upon initialization. So here's my question:
Would it be more efficient to use a C-style dynamic array, the size of which I can decide and allocate inside a parameterized constructor, like so?
class hurtBox {
private:
int ***hurtBoxMatrix;
public:
hurtBox(int l, int w, int h) {
hurtBoxMatrix = new int**[l];
for (int i = 0; i < l; i++) {
hurtBoxMatrix[i] = new int*[w];
for (int j = 0; j < w; j++) {
hurtBoxMatrix[i][j] = new int[h] ();
}
}
}
};
Or, would a vector that I push elements into, up to my desired dimensions, suffice?
class hurtBox {
private:
vector<vector<vector<int>>> hurtBoxMatrix;
public:
hurtBox(int l, int w, int h) {
for (int i = 0; i < l; i++) {
hurtBoxMatrix.push_back(vector<vector<int>>);
for (int j = 0; j < w; j++) {
hurtBoxMatrix[i].push_back(vector<int>);
for (int k = 0; k < h; k++) {
hurtBoxMatrix[i][j].push_back(0);
}
}
}
}
};
I imagine the former, since that first allocation is constant time, right? Is there a way to do this that's better than either of these?
Thanks in advance.
You'd be better off simply allocating the 3D array in a single allocation, and use indexing to access the elements. Allocation for the std::vector storage can then be handled in the constructor for std::vector.
In general it's best to avoid:
multiple allocations
repeatedly calling push_back
class hurtBox {
private:
vector<int> hurtBoxMatrix;
int m_l;
int m_w;
int m_h;
public:
hurtBox(int l, int w, int h)
: hurtBoxMatrix(l * w * h), m_l(l), m_w(w), m_h(h) {}
int& operator (int i, int j, int k) {
return hurtBoxMatrix[ I*m_w*m_h + j*m_w + k ];
}
const int operator (int i, int j, int k) const {
return hurtBoxMatrix[ i*m_w*m_h + j*m_w + k ];
}
};
Is there a way to tell the compiler that I've allocated a memory of size N * M and I wanna treat this pointer as N * M array? In other words, is there a way to write something like this?:
int arr[N][M] = (int[N][M])malloc(N * M * sizeof(int));
arr[x][y] = 123;
I know that the compiler doesn't know the dimensions of the array, all it knows is that that's a pointer. so my question is: can I somehow tell the compiler that this pointer returned by malloc is an array pointer and it's dimensions are N * M? I can use an array to pointers, pointer to arrays or pointer to pointers, but in all cases I'll have to lookup 2 addresses. I want to have a contiguous memory on the heap and treat it as a multidimensional array. just like how I would write:
int arr[N][M];
Is there any way to achieve that?
In a C++ program you should use the operator new.
As for malloc then in C++ M shall be a constant expression if you want to allocate a two-dimensional array.
You can write for example
int ( *arr )[M] = ( int ( * )[M] )malloc( N * M * sizeof(int) );
or
int ( *arr )[M] = ( int ( * )[M] )malloc( sizeof( int[N][M] ) );
If to use the operator new then the allocation can look like
int ( *arr )[M] = new int[N][M];
If M is not a compile-time constant then you can use the standard container std::vector as it is shown in the demonstrative program below
#include <iostream>
#include <vector>
int main()
{
size_t n = 10, m = 10;
std::vector<std::vector<int>> v( n, { m } );
return 0;
}
What you want is a "matrix" class like
template <typename T>
class matrix
{
size_t len;
size_t width;
std::vector<T> data;
public:
matrix(size_t len, size_t width) : len(len), width(width), data(len*width) {}
T& operator()(size_t row, size_t col) { return data[width * row + col]; }
const T& operator()(size_t row, size_t col) const { return data[width * row + col]; }
size_t size() const { return len * width; }
};
int main(int argc, char const *argv[])
{
matrix<int> m(5, 7);
m(3, 3) = 42;
std::cout << m(3, 3);
}
This keeps all of the data in a single contiguous buffer, and doesn't have any undefined behavior unlike all the other examples that use malloc. It's also RAII, and you don't have to write any copy or move constructors since all of the members "do the right thing" with the compiler provided defaults. You can make this class more complicated, provide a proxy object so you can overload operator[] and be able to do m[][], but at it's base this is what you want.
If you what to avoid use of stack and you need large single block of data to keep two dimensional array of constant size (know at compile time) the this is the best cleanest way to do it:
std::vector<std::array<int, M>> arr(N);
arr[x][y] = 3;
Now if you need M is a value known at run-time, it would be best to use boost::multi_array
I do not see a reason to use malloc.
You can do exactly what you want with a helper function. This let's you specify the array size at runtime, and it uses malloc as requested (although typically you should be using new):
#include <iostream>
#include <string>
#include <memory>
template <class T>
T** Get2DMalloc(size_t m, size_t n) {
T** ret = (T**)malloc(sizeof(T*) * m);
for (size_t i = 0; i < m; ++i) {
ret[i] = (T*)malloc(sizeof(T) * n);
}
return ret;
}
template <class T>
void Free2D(T** arr, size_t m, size_t n) {
for (int i = 0; i < m; ++i) {
free(arr[i]);
}
free(arr);
}
int main() {
int m = 3;
int n = 3;
int** a = Get2DMalloc<int>(3, 3);
for (int x = 0; x < m; ++x) {
for (int y = 0; y < n; ++y) {
a[x][y] = x * m + y;
}
}
for (int i = 0; i < m * n; ++i) {
std::cout << a[i / m][i % n] << std::endl;
}
Free2D<int>(a, m, n);
system("pause");
return 0;
}
I want to declare an array of arrays or multidimensional array without knowing the size.
I want to do something similar to what I did in this cases with simple arrays:
int *array;
cin >> size;
array = new int[size];
Maybe I can loop to initialize a pointer of pointers like this:
int **array;
cin >> rows >> col;
array = new *int[rows]
for (int i = 0; i < rows; ++i)
array[i] = new int[col];
But I would prefer to not do this if a better solution exists.
Why not use std::vector?
std::vector<std::vector<int> > array;
If you don't want to use an array of pointers, you could use one large array that you allocate dynamically after you get the size and access it as an array of rows.
int rows = 10;
int columns = 20;
int* array = new int[rows * columns];
for (int count = 0; count < rows; count++)
{
int* row = &array[count * columns];
for (int inner_count = 0; inner_count < columns; inner_count++)
{
int* element = &row[inner_count];
//do something
}
}
delete [] array;
You're pretty much going to have to go with the loop version. You can make one slight improvement, which is to allocate one big block and then build your own int* index into it:
int **array;
int *storage;
cin >> rows >> col;
array = new *int[rows];
storage = new int[rows*col];
for (int i = 0; i < rows; ++i)
array[i] = storage + col * i;
This has the nice property that you can still use array[i][j] syntax for accessing the array.
You could use a single std::vector to contain the entire two dimensional array and wrap it in a class to hide the details. Here's an example, it uses a data( row, col ) member function that returns a reference to the element at row and col. I included an example 2 dimensional matrix of int where each entry in the array is initialized to the product of its row and col. When an instance of this class goes out of scope, the default destructor will get called and release the memory, that way you don't have to remember to call delete[] to release the memory. All elements of the matrix will be contiguous in memory, this is cache friendly and should give you good performance.
#include <iostream>
#include <vector>
#include <stdexcept>
template <typename T>
class matrix {
std::vector<T> data_;
public:
size_t const rows_;
size_t const cols_;
matrix(size_t rows, size_t cols)
: rows_(rows)
, cols_(cols)
, data_( rows * cols )
{}
T& data( size_t row, size_t col ) {
if (row > rows_ || col > cols_) throw std::out_of_range("matrix");
return data_[ row * cols_ + col ];
}
};
int main( int argc, char** argv )
{
matrix<int> array(100,100);
for(size_t r=0; r < array.rows_; ++r) {
for(size_t c=0; c < array.cols_; ++c) {
array.data(r,c) = r * c;
}
}
std::cout << "8 x 7 = " << array.data(8,7) << std::endl;
return 0; // array goes out of scope here, memory released automatically
}
When you run this you will get
8 x 7 = 56
If you care, you can have a little bit more convenience by have a helper
template <typename T>
struct C3DArray
{
vector<vector<vector<T>>> m;
C3DArray(int size_x, int size_y, int size_z)
: m(make(T(), size_z, size_y, size_x))
{ }
template <typename U> static std::vector<U> make(U v, size_t n) {
return { n, std::move(v) };
}
template <typename U, typename... Dim> static auto make(U v, size_t n, Dim... other)
-> std::vector<decltype(make(v, other...))> {
return { n, make(v, other...) };
}
};
This uses variadics. Use it like this:
C3DArray<int> arr(3,4,20);
I am trying to create a class as such:
class CLASS
{
public:
//stuff
private:
int x, y;
char array[x][y];
};
Of course, it doesn't work until I change int x, y; to
const static int x = 10, y = 10;
Which is impractical, because I am trying to read the values of x and y from a file. So is there any way to initialize an array with non-contant values, or declare an array and declare its size on different statements? And I know this would probably require the creation of an array class, but I'm not sure where to start on this, and I don't want to create a 2D dynamic list when the array itself is not dynamic, just the size is not known at compile-time.
use vector.
#include <vector>
class YourClass
{
public:
YourClass()
: x(read_x_from_file()), y(read_y_from_file())
{
my_array.resize(x);
for(int ix = 0; ix < x; ++ix)
my_array[ix].resize(y);
}
//stuff
private:
int x, y;
std::vector<std::vector<char> > my_array;
};
The compiler need to have the exact size of the class when compiling, you will have to use the new operator to dynamically allocate memory.
Switch char array[x][y]; to char** array; and initialize your array in the constructor, and don't forget to delete your array in the destructor.
class MyClass
{
public:
MyClass() {
x = 10; //read from file
y = 10; //read from file
allocate(x, y);
}
MyClass( const MyClass& otherClass ) {
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
// This can be replace by a memcopy
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<x ; ++j )
array[i][j] = otherClass.array[i][j];
}
~MyClass(){
deleteMe();
}
void allocate( int x, int y){
array = new char*[x];
for( int i = 0; i < y; i++ )
array[i] = new char[y];
}
void deleteMe(){
for (int i = 0; i < y; i++)
delete[] array[i];
delete[] array;
}
MyClass& operator= (const MyClass& otherClass)
{
if( this != &otherClass )
{
deleteMe();
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<y ; ++j )
array[i][j] = otherClass.array[i][j];
}
return *this;
}
private:
int x, y;
char** array;
};
*EDIT:
I've had the copy constructor
and the assignment operator
Not in that manner, as in c++, c-style array sizes have to be known at compile time, with some vendor specific extensions allowing certain runtime sizes (to enhance compatibility with C99), but not in the situation you are describing (if you are interested, here's a description). The easiest thing to do would be:
std::vector< std::vector<char> > array;
And apply the size in the constructor:
array.resize(x);
for(std::vector< std::vector<char> >::iterator curr(array.begin()),end(array.end());curr!=end;++curr){
curr->resize(y);
}
There are many advantages of vector over c style arrays, see here
Put all the memory into one block.
Because it is private you can then get your access methods to retrieve the correct value.
Quick example:
#include <vector>
#include <iostream>
class Matrix
{
public:
class Row
{
public:
Row(Matrix& p,unsigned int x)
:parent(p)
,xAxis(x)
{}
char& operator[](int yAxis)
{
return parent.data(xAxis,yAxis);
}
private:
Matrix& parent;
unsigned int xAxis;
};
Matrix(unsigned int x,unsigned int y)
:xSize(x)
,ySize(y)
,dataArray(x*y)
{}
Matrix::Row operator[](unsigned int xAxis)
{
return Row(*this,xAxis);
}
char& data(unsigned int xAxis,unsigned int yAxis)
{
return dataArray[yAxis*xSize + xAxis];
}
private:
unsigned int xSize;
unsigned int ySize;
std::vector<char> dataArray;
};
int main()
{
Matrix two(2,2);
two[0][0] = '1';
two[0][1] = '2';
two[1][0] = '3';
two[1][1] = '4';
std::cout << two[1][0] << "\n";
std::cout << two.data(1,0) << "\n";
}
Take a look at boost::multi_array.
You can't allocate or initialize a global or static array declaratively using non-constant values (compile-time). It's possible for local arrays though (C99 variable sized arrays, as their initializer essentially runs at runtime every time the function is executed).
For your situation, I suggest using a pointer instead of an array and create the actual array dynamically at runtime (using new):
class CLASS
{
public:
CLASS(int _x, int _y) : x(_x), y(_y) {
array = new char*[x];
for(int i = 0; i < x; ++i)
array[i] = new char[y];
}
~CLASS() {
for (int i = 0; i < x; ++i)
delete[] array[i];
delete[] array;
}
//stuff
private:
int x, y;
char **array;
};
You can allocate memory to your 2-dimensional array in the constructor and free it in the destructor. The simplest way:
array = (char **)malloc(sizeof(char *) * x);
if (array) {
for (i = 0; i < x; i++) {
array[i] = (char *)malloc(sizeof(char) * y);
assert(array[i]);
}
}
If the size is not known at compile time, the array is dynamic. What you could do to keep it static is to make them larger than your largest expected size.
If you want a dynamically sized array as a class member, you need to array new it and assign that value to a pointer. The char array[size] syntax is only for statically-sized arrays.
Better yet, you really should use an std::vector< std::vector<char> >, there are very few good reasons to manually work with dynamically sized arrays these days.
I'm trying to make a pointer point to a 2D array of pointers. What is the syntax and how would I access elements?
By the letter of the law, here's how to do it:
// Create 2D array of pointers:
int*** array2d = new (int**)[rows];
for (int i = 0; i < rows; ++i) {
array2d[i] = new (int*)[cols];
}
// Null out the pointers contained in the array:
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
array2d[i][j] = NULL;
}
}
Be careful to delete the contained pointers, the row arrays, and the column array all separately and in the correct order.
However, more frequently in C++ you'd create a class that internally managed a 1D array of pointers and overload the function call operator to provide 2D indexing. That way you're really have a contiguous array of pointers, rather than an array of arrays of pointers.
It depends. It can be as simple as:
int main()
{
int* data[10][20]; // Fixed size known at compile time
data[2][3] = new int(4);
}
If you want dynamic sizes at runtime you need to do some work.
But Boost has you covered:
int main()
{
int x;
int y;
getWidthAndHeight(x,y);
// declare a 2D array of int*
boost::multi_array<int*,2> data(boost::extents[x][y]);
data[2][3] = new int(6);
}
If you are fine with jagged arrays that can grow dynamically:
int main()
{
std::vector<std::vector<int*> > data;
data.push_back(std::vector<int*>(10,NULL));
data[0][3] = new int(7);
}
Note: In all the above. I assume that the array does not own the pointer. Thus it has not been doing any management on the pointers it contains (though for brevity I have been using new int() in the examples). To do memory management correctly you need to do some more work.
int *pointerArray[X][Y];
int **ptrToPointerArray = pointerArray;
That's how you make a true (contiguous in memory) multidimensional array.
But realize that once you cast a multidimensional array to a pointer like that, you lose the ability to index it automatically. You would have to do the multidimensional part of the indexing manually:
int *pointerArray[8][6]; // declare array of pointers
int **ptrToPointerArray = &pointerArray[0][0]; // make a pointer to the array
int *foo = pointerArray[3][1]; // access one element in the array
int *bar = *(ptrToPointerArray + 3*8 + 1); // manually perform row-major indexing for 2d array
foo == bar; // true
int *baz = ptrToPointerArray[3][1]; // syntax error
double** array = new double*[rowCnt];
for (int row = 0; row < rowCnt; ++row)
array[row] = new double[colCnt];
for (int row = 0; row < rowCnt; ++row)
for (int col = 0; col < colCnt; ++col)
array[row][col] = 0;
You could try Boost::MultiArray.
Check out this page for details.
:)
I had these once in a piece of code I wrote.
I was the laughing stock of the team when the first bugs leaked out. On top of that we use Hungarian notation, leading to a name like papChannel - a pointer to an array of pointers...
It's not nice. It's nicer to use typedefs to define a 'row of columns' or vice versa. Makes indexing more clear, too.
typedef int Cell;
typedef Cell Row[30];
typedef Row Table[20];
Table * pTable = new Table;
for( Row* pRow = *pTable; pRow != *pTable+_countof(*pTable); ++pRow ) {
for( Cell* pCell = *pRow; pCell != *pRow + _countof(*pRow); ++pCell ) {
... do something with cells.
}
}
You can define a vector of vectors:
typedef my_type *my_pointer;
typedef vector<vector<my_pointer> > my_pointer2D;
Than create a class derived from my_pointer2D, like:
class PointersField: public my_pointer2D
{
PointsField(int n, int m)
{
// Resize vectors....
}
}
PointsField pf(10,10); // Will create a 10x10 matrix of my_pointer
I prefer to use the () operator. There are lots of reasons for this (C++ FAQs 13.10). Change the internal representation to a std::vector if you like:
template <class T, int WIDTH, int HIEGHT>
class Array2d
{
public:
const T& operator ()(size_t col, size_t row) const
{
// Assert col < WIDTH and row < HIEGHT
return m_data [( row * WIDTH + col)];
}
T& operator ()(size_t col, size_t row)
{
// Assert col < WIDTH and row < HIEGHT
return m_data [( row * WIDTH + col)];
}
private:
T m_data[WIDTH * HIEGHT];
};
You can use it like this:
Array2d< Object*, 10, 10 > myObjectArray;
myObjectArray(5,6) = new Object();
See my code. It works on my FC9 x86_64 system:
#include <stdio.h>
template<typename t>
struct array_2d {
struct array_1d {
t *array;
array_1d(void) { array = 0; }
~array_1d()
{
if (array) {
delete[] array;
array = 0;
}
}
t &operator[](size_t index) { return array[index]; }
} *array;
array_2d(void) { array = 0; }
array_2d(array_2d<t> *a) { array = a->array; a->array = 0; }
void init(size_t a, size_t b)
{
array = new array_1d[a];
for (size_t i = 0; i < a; i++) {
array[i].array = new t[b];
}
}
~array_2d()
{
if (array) {
delete[] array;
array = 0;
}
}
array_1d &operator[](size_t index) { return array[index]; }
};
int main(int argc, char **argv)
{
array_2d<int> arr = new array_2d<int>;
arr.init(16, 8);
arr[8][2] = 18;
printf("%d\n",
arr[8][2]
);
return 0;
}
Effo UPD: a response to "Isn't that an array of pointers to arrays?", adding the example of array of pointers, very simple:
int main(int argc, char **argv)
{
array_2d<int*> parr = new array_2d<int*>;
int i = 10;
parr.init(16, 8);
parr[10][5] = &i;
printf("%p %d\n",
parr[10][5],
parr[10][5][0]
);
return 0;
}
Did I still misunderstand your question?
And you could even
typedef array_2d<int*> cell_type;
typedef array_2d<cell_type*> array_type;
int main(int argc, char **argv)
{
array_type parr = new array_type;
parr.init(16, 8);
parr[10][5] = new cell_type;
cell_type *cell = parr[10][5];
cell->init(8, 16);
int i = 10;
(*cell)[2][2] = &i;
printf("%p %d\n",
(*cell)[2][2],
(*cell)[2][2][0]
);
delete cell;
return 0;
}
It also works on my FC9 x86_64 system.