How to allocate a 2D array of pointers in C++ - c++

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.

Related

c++ 3d array function returns

So i've got this 3 dimensional array that looks like this:
int map[100][100][100];
and I want to use it as a return type for a function, whether as a pointer or whatever like so:
int* World::CreateCell() {
int map[100][100][100];
return map;
}
However I cannot find the appropriate return type for a 3d array, it will not let me use an int* like you can for a 2D array.
Even things like this don't work:
int a[100][100][100];
int* b = a;
VS seems to think the data type is int*(100)(100) but that makes no sense and doesn't work.
For what it's worth, I've googled this and seen no solutions. Thank you
Since you want 3D C-style array, you need to have a pointer to a pointer to a pointer, i.e., int***. Also, you need to allocate the memory if you use a creation function like this. Otherwise, you return the statically allocated memory from that function.
Here is a quick example of how to do it:
#include <iostream>
static int*** create_cell() {
constexpr std::size_t n = 100;
int*** map = new int**[n];
for (std::size_t i = 0u; i < n; ++i) {
map[i] = new int*[n];
for (std::size_t j = 0u; j < n; ++j) {
map[i][j] = new int[n];
}
}
return map;
}
static void delete_cell(int***& map) {
constexpr std::size_t n = 100;
for (std::size_t i = 0u; i < n; ++i) {
for (std::size_t j = 0u; j < n; ++j) {
delete[] map[i][j];
}
delete[] map[i];
}
delete[] map;
}
int main()
{
int*** a = create_cell();
a[0][0][0] = 1;
std::cout << "a[0][0][0] = " << a[0][0][0] << std::endl;
delete_cell(a);
return 0;
}
It depends on your use case: BUT for modern c++ you can ease your life using containers from the stl such as std::vector and std::array. Check here for reference: std::array and std::vector
For example, you can define your 3D types:
#include <array>
#include <vector>
using vector_3d = std::vector<std::vector<std::vector<int>>>;
using array_3d = std::array<std::array<std::array<int, 100>, 100>, 100>;
and then use them as:
array_3d b;
b[0][0][0] = 1;
std::cout << "b[0][0][0] = " << b[0][0][0] << std::endl;
First you should
Never return a reference or a pointer to a local non-static variable.
Now coming to your question:
I want to use it as a return type for a function, whether as a pointer or whatever like so.However I cannot find the appropriate return type for a 3d array.
This(below) is how you can do it for a 3D array. Basically there are 2 ways to solve this:
Method 1
//CreateCell is a function that returns a pointer to a 3D array of the size 100,100,100
int (*CreateCell())[100][100][100] {
int map[100][100][100];
return &map;
}
Method 1 works as can be seen here.
Method 2
//CreateCell is a function that returns a pointer to a 3D array of the size 100,100,100
auto CreateCell() -> int(*)[100][100][100] {
int map[100][100][100];
return &map;
}
Method 2 uses trailing return type and works as can be seen here.
Note
Both methods return a pointer to a local variable which must be avoided. I have given/written the answer just so that you can see how to return a pointer for a 3D array as you desired. You can instead create and return a 3D `std::vector` by value.
Consider using a simple wrapper around your matrix:
struct Wrapper { int Mat[100][100][100] = {0}; };
The signature would then become something like:
Wrapper *foo(...) { ... }
Here is simple working example:
#include <iostream>
struct Wrapper { int Mat[100][100][100] = {0}; };
Wrapper *inc(Wrapper *w)
{
for (int i=0;i<100;i++)
for (int j=0;j<100;j++)
for (int k=0;k<100;k++)
w->Mat[i][j][k] += (i+j+k);
return w;
}
int main(int argc, char **argv)
{
Wrapper w;
Wrapper *out = inc(&w);
std::cout << out->Mat[5][6][7] << "\n";
return 0;
}

3D multidimensional array to "row" pointer

I was wondering how i can access multidimensional rows in a 3D via pointer like this:
int ccc[8][7][2] = ....;
for(int i=0;i<8;i++)
{
int** cc_i = ccc[i];
for(int j=0;j<7;j++)
{
int* c_j = cc_i[j];
int th0 = c_j[0];
int th1 = c_j[0];
}
}
You can't, because a pointer to a pointer is not the same as an array of arrays. The layout in memory is radically different.
You can however declare e.g. cc_i as a pointer to an array, like
int (*cc_i)[2] = ccc[i];
Like this
int ccc[8][7][2] = ....;
for(int i=0;i<8;i++)
{
int (*cc_i)[2] = ccc[i];
for(int j=0;j<7;j++)
{
int *c_j = cc_i[j];
int th0 = c_j[0];
int th1 = c_j[0];
}
}

Declare a multidimentional array without the size

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);

Is there a way to initialize an array with non-constant variables? (C++)

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.

Delaying array size in class definition in C++?

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];
}