Via stackoverflow threads like this one, I discovered that you could use an array of pointers to manage a 2D array. In the past I used to use pointer to pointer to store 2D arrays, but now I have a requirement to store my data in contiguous memory, so pointer to pointer format doesn't work anymore.
A raw 2D array is an alternative to array of pointers, but raw 2D array doesn't work for me because I want to be able to allocate storage in the heap and not on the stack because my container can be very large and I might encounter stack overflow if I use vanilla 2D array.
My question is about how memory is allocated for array of pointers. I use new operator like below (see my constructor) to allocate my array of pointers
#include <iostream>
using namespace std;
template<typename DataType, unsigned numRows, unsigned numCols>
class Container2D {
public:
Container2D() {
m_data = new DataType[numRows][numCols];
}
~Container2D() {
delete [] m_data;
}
DataType* getData() { return &m_data[0][0]; }
private:
DataType (*m_data)[numCols];
};
int main() {
Container2D<int, 3, 3> container;
return 0;
}
Does new DataType[numRows][numCols] allocate the entire 2D array on the heap or does it allocate numRows pointers on the heap while allocating numCols objects of type DataType on the stack?
In a pointer to pointer scenario (where I'd define my storage as DataType** m_data), I know for a fact that both dimensions of my array are allocated on the heap and I would call delete m_data[i] for each column and then call delete[] m_data to free my row data. In the array of pointers scenario, I'm not sure if my destructor above is freeing up data correctly.
One way is to use a 1D contiguous array and implement the 2D index to 1D index mapping instead:
#include <iostream>
#include <cassert>
using namespace std;
template<typename DataType, unsigned numRows, unsigned numCols>
class Container2D {
public:
Container2D() { m_data = new DataType[numRows * numCols]; }
~Container2D() { delete [] m_data; }
inline DataType operator()(unsigned i, unsigned j) const {
assert( 0 <= i && i < numRows);
assert( 0 <= j && j < numCols);
return m_data[i*numCols+j];
}
inline DataType& operator()(unsigned i, unsigned j) {
// same as above, but this allows inplace modifications
assert( 0 <= i && i < numRows);
assert( 0 <= j && j < numCols);
return m_data[i*numCols+j];
}
private:
DataType* m_data;
};
int main() {
Container2D<int, 3, 3> container;
int x = container(0,0); // retrieve the element at (0,0);
container(1,2) = 9; // modify the element at (1,2);
// int y = container(3,0); // triggers assertion errors for out-of-bound indexing
return 0;
}
Notes:
If numRows and numCols do not change for a specific class instance, new and delete are not necessary in this case. If they do dynamically change, it is better to store them as member variables instead of template parameters. If numRows and numCols are too large, one can dynamically allocate Container2D objects as a whole.
As #GoswinvonBrederlow commented, there is no difference between this and new m_data[numRows][numCols] in terms of memory layout, but this convention makes it easier to extend to higher dimensions.
Does new DataType[numRows][numCols] allocate the entire 2D array on the heap or does it allocate numRows pointers on the heap while allocating numCols objects of type DataType on the stack?
When you write
DataType arr[numRows][numCols];
the memory will be in one contiguos block as you mentioned. Nothing changes there when you use new. It will allocate one contiguos block of memory of the specified type. There is no hidden array of pointers into the real data.
Related
Am I breaking C++ coding conventions writing a helper function which allocates a 2D array outside main()? Because my application calls for many N-dimensional arrays I want to ensure the same process is followed. A prototype which demonstrates what I am doing :
#include <iostream>
// my helper function which allocates the memory for a 2D int array, then returns its pointer.
// the final version will be templated so I can return arrays of any primitive type.
int** make2DArray(int dim1, int dim2)
{
int** out = new int* [dim1];
for (int i = 0; i < dim2; i++) { out[i] = new int[dim2];}
return out;
}
//helper function to deallocate the 2D array.
void destroy2DArray(int** name, int dim1, int dim2)
{
for (int i = 0; i < dim2; i++) { delete[] name[i]; }
delete[] name;
return;
}
int main()
{
int** test = make2DArray(2,2); //makes a 2x2 array and stores its pointer in test.
//set the values to show setting works
test[0][0] = 5;
test[0][1] = 2;
test[1][0] = 1;
test[1][1] = -5;
// print the array values to show accessing works
printf("array test is test[0][0] = %d, test[0][1] = %d, test[1][0] = %d, test[1][1] = %d",
test[0][0],test[0][1],test[1][0],test[1][1]);
//deallocate the memory held by test
destroy2DArray(test,2,2);
return 0;
}
My concern is this may not be memory-safe, since it appears I am allocating memory outside of the function in which it is used (potential out-of-scope error). I can read and write to the array when I am making a single small array, but am worried when I scale this up and there are many operations going on the code might access and alter these values.
I may be able to sidestep these issues by making an array class which includes these functions as members, but I am curious about this as an edge case of C++ style and scoping.
There is a difference between allocating 2D arrays like this and what you get when you declare a local variable like int ary[10][10] that based on your statement
My concern is that this operation may not be memory-safe, since it
appears that I am allocating memory for an array outside of the
function in which it is used (potential out-of-scope error)
I am guessing you do not fully understand.
You are allocating arrays on the heap. Declaring a local variable like int ary[10][10] places it on the stack. It is the latter case where you need to worry about not referencing that memory outside of its scope-based lifetime; that is, it is the following that is totally wrong:
//DON'T DO THIS.
template<size_t M, size_t N>
int* make2DArray( ) {
int ary[M][N];
return reinterpret_cast<int*>(ary);
}
int main()
{
auto foo = make2DArray<10, 10>();
}
because ary is local to the function and when the stack frame created by the call to make2DArray<10,10> goes away the pointer the function returns will be dangling.
Heap allocation is a different story. It outlives the scope in which it was created. It lasts until it is deleted.
But anyway, as others have said in comments, your code looks like C not C++. Prefer an std::vector<std::vector<int>> rather than rolling your own.
If you must use an array and are allergic to std::vector, create the 2d array (matrix) as one contiguous area in memory:
int * matrix = new int [dim1 * dim2];
If you want to set the values to zero:
std::fill(matrix, (matrix + (dim1 * dim2)), 0);
If you want to access a value at <row, column>:
int value = matrix[(row * column) + column];
Since the matrix was one allocation, you only need one delete:
delete [] matrix;
I was introduced to pointers, I quite get it. but I don't know how to store variables in the vector class using pointers.
Here is what I got from my understanding but how should I complete it?
class Vector{
int size;
int* element;
public:
vector(int x);
int size() const { return size }
};
first, you need to define a value that stores the current size - (number of elements inside the vector) - to be able to add values at the end of the vector.
int curr_vec_size;
also, the actual size of the vector should be saved in a variable to check every time you add a value that allocated memory is not full
int memory_size;
second, you need to allocate memory dynamically by using "new" in the constructor
vector(int size)
{
element = new int[size]; //allocating memory (array of integers)
memory_size= size; //size of allocated memory
curr_vec_size= 0; //no values in the vector
}
then you can make a method that takes an int value and adds it to the dynamic array.
void add_value(int passed_val)
{
if(curr_vec_size < memory_size)
{
element[curr_vec_size]=passed_val; //adding the value in the vector
curr_vec_size ++; //because you have added a new value
}
else
cout<<"vector is full \n";
}
Finally, don't forget to delete the memory you've allocated by using destructors that deletes the pointer to this allocated memory.
vector()
{
delete[] element;
}
To complete what you started, you simply need to use new[] operator to allocate memory to store your int values:
vector(int x)
{
size = x;
element = new int[size]; // this allocates an array of int with a size of "size"
}
Then, you can use element[i] to access i's element of your array.
You'll later need (it's a must) to release allocatd memory to prevent memory leak by implementing a destructor:
~vector()
{
delete [] element;
}
Note that you should (must) also also follow at least the rule of 3 to have you vector be copiable.
how to allocate run time memory to an array of size[4][3]?
i.e int a[4][3]
If need is to allocate memory to an array at run time than how to allocate memory to 2D array or 3D array.
Editing the answer based on comments. Allocate separately for each dimension. For a 2D array a 2 level allocation is required.
*a = (int**)malloc(numberOfRows*sizeof(int*));
for(int i=0; i<numberOfRows; i++)
{
(*arr)[i] = (int*)malloc(numberOfColumns*sizeof(int));
}
The simplest way to allocate dynamically an array of type int[4][3] is the following
int ( *a )[3] = new int[4][3];
// some stuff using the array
delete []a;
Another way is to allocate several arrays. For example
int **a = new int * [4];
for ( size_t i = 0; i < 4; i++ ) a[i] = new int[3];
// some stuff using the array
for ( size_t i = 0; i < 4; i++ ) delete []a[i];
delete []a;
What have you tried. new int[4][3] is a perfectly valid
expression, and the results can be assigned to a variable with the
appropriate type:
int (*array2D)[3] = new int[4][3];
Having said that: I can't really think of a case where this
would be appropriate. Practically speaking, anytime you need
a 2 dimensional array, you should define a class which
implements it (using std::vector<int> for the actual memory).
A pure C approach is the following:
int (*size)[4][3];
size = malloc(sizeof *size);
/* Verify size is not NULL */
/* Example of access */
(*size)[1][2] = 89;
/* Do something useful */
/* Deallocate */
free(size);
The benefit is that you consume less memory by not allocating intermediate pointers, you deal with a single block of memory and deallocation is simpler. This is especially important if you start to have more than 2 dimensions.
The drawback is that the access syntax is more complicated, as you need to dereference a pointer before being able to index.
Use calloc, i guess this will do.
int **p;
p=(int**)calloc(4,sizeof(int));
In C you can use pointer to pointer
AS #Lundin mentioned this is not 2D array. It is a lookup table using pointers to fragmented memory areas allocated all over the heap.
You need to allocate how many pointers you need and then allocate each pointer. you can allocate fixed size or varaible size depending on your requirement
//step-1: pointer to row
int **a = malloc(sizeof(int *) * MAX_NUMBER_OF_POINTERS);
//step-2: for each rows
for(i = 0; i < MAX_NUMBER_OF_POINTERS; i++){
//if you want to allocate variable sizes read them here
a[i] = malloc(sizeof(int) * MAX_SIZE_FOR_EACH_POINTER); // where as if you use character pointer always allocate one byte extra for null character
}
Where as if you want to allocate char pointers avoid using sizeof(char) inside for loop. because sizeof(char) == 1 and do not cast malloc result.
see How to declare a 2d array in C++ using new
You could use std::vector<> since it is a templated container (meaning array elements can be whatever type you need). std::vector<> allows for dynamic memory usage (you can change the size of the vector<> whenever you need to..the memory is allocated and free'd automatically).
For example:
#include <iostream>
#include <vector>
using namespace std; // saves you from having to write std:: in front of everthing
int main()
{
vector<int> vA;
vA.resize(4*3); // allocate memory for 12 elements
// Or, if you prefer working with arrays of arrays (vectors of vectors)
vector<vector<int> > vB;
vB.resize(4);
for (int i = 0; i < vB.size(); ++i)
vB[i].resize(3);
// Now you can access the elements the same as you would for an array
cout << "The last element is " << vB[3][2] << endl;
}
You can use malloc() in c or new in c++ for dynamic memory allocation.
I need to have a 2D array of double.
Its width is around 900. Its height as well (the same width value).
Dealing with two loops (one for the width and one for the height), I really need to get access to all the pixels of the 900X900 image that I will process.
The size of the array is too big (error when specifying the number of raw and column).
I thought about establishing that with a dynamic array to optimize the time of calculation and to free the memory everytime I deal with one pixel on the two loops.
But I really cannot find the syntax I would like to have to declare a 2D dynamic array (malloc, setting array element values and freeing the memory).
Wrap it in a class:
class Matrix2D {
typedef std::vector<double> Column;
std::vector<Column> columns;
public:
Matrix2D(unsigned int width, unsigned int height) :
columns(width, Column(height)) {
}
double& at(unsigned int i, unsigned int j) {
return columns[i][j];
}
};
Matrix2D matrix(900, 900);
matrix.at(45, 65) = 1234.5678;
I need to have a 2D array of double
Since you are using C++ you should use STL classes that will take care of ugly memory management for you. So you are actually looking for std::vector< std::vector<double> >, or for the sake of the readability of your code:
#include <vector>
typedef std::vector<double> DVector; // row represented by vector of doubles
typedef std::vector<DVector> MyVector; // 2D array as a vector of these rows
And then avoid using dynamic allocation wherever it's possible to do so. Take advantage of RAII idiom:
{
MyVectorarr; // vector object with automatic storage duration
} // <-- vector is automatically destructed when execution goes out of scope
Questions that might help you:
Multi-dimensional vector
Initialization of a vector of vectors?
vector of vector
I associate malloc with pure C, not C++ (as the prior answer points yout, you should use std::vector). However, if you really want to:
// allocate the memory in a block
double* block = (double *) malloc(sizeof(double) * xSize * ySize);
// allocate memory for the accessor array
double* accessor = (double*) malloc(sizeof(double*) * xSize);
// assign memory addresses
double* curPtr = block;
for (int i = 0; i < xSize; ++i) {
accessor[i] = curPtr;
curPtr += ySize;
}
// you can now access the array via accessor[x][y]
// now need to free malloced memory:
free(accessor);
free(block);
If you do it this way, I highly suggest tying it to the RAII pattern, otherwise you'll eventually get a memory leak. Using the STL's containers is a better approach.
I am trying to develop a class to backup & restore console screen buffers. Here's my code in progress.
class CBuff
{
private:
CONST WCHAR max_unit;
HANDLE hnd;
CHAR_INFO *stor_buff;
COORD s_buff_sz;
COORD d_buff_cod;
SMALL_RECT read_region;
public:
CBuff():max_unit(10)
{}
~CBuff(){}
void Initiate(HANDLE hndl, SHORT buff_x, SHORT buff_y, SHORT buff_width, SHORT buff_height)
{
hnd=hndl;
stor_buff=new CHAR_INFO[buff_width*buff_height]();
s_buff_sz.X=buff_width;
s_buff_sz.Y=buff_height;
d_buff_cod.X=0;
d_buff_cod.Y=0;
read_region.Left=0;
read_region.Top=0;
read_region.Right=buff_width-1;
read_region.Bottom=buff_height-1;
}
int Backup()
{
if(!ReadConsoleOutput(hnd,stor_buff,s_buff_sz,d_buff_cod,&read_region)) return -1;
return 0;
}
int Restore()
{
if(!WriteConsoleOutput(hnd,stor_buff,s_buff_sz,d_buff_cod,&read_region)) return -1;
return 0;
}
int Backup_mp()
{/*incomplete*/}
int Restore_mp()
{/*incomplete*/}
};
It works with Backup() & Restore() fine. And then I tried to make another version of Backup, Backup_mp(handle, backup_num), that will create multiple backups from different console buffer instances. I planned on converting last four variables in private space into array, so that a index value (backup_num) can be used for different backup point. An allocation like this
stor_buff=new CHAR_INFO[index][buff_width*buff_height]();
is not working.
What option do I have?
Also, can I use CONST WCHAR max_unit as the parameter for an array like s_buff_sz[max_unit] ?
You're using C++, so make use of it: Use std::vector.
//Declaration of your buffers:
std::vector< std::vector<CHAR_INFO> > store_buffers;
//Append a new buffer entry:
store_buffers.push_back( std::vector<CHAR_INFO>( buff_width * buff_height ) );
// Pass buffer with index index to WinAPI functions:
..., store_buffers[index].data(), s_buff_sz, ...
If using C++11, you can use std::array for the fixed sized dimension (instead of std::vector, which is variable), but that's not critical.
To allocate a two-dimensional array in heap (using new), you need to allocate the pointers first, and then the arrays. Example:
stor_buff = new CHAR_INFO* [buff_height]; // Allocate rows (pointers
for(int index = 0; index < buff_height; ++index)
stor_buff[index] = new CHAR_INFO[buff_width];
And use them directly, as if store_buff is 2D array. For deallocation, you need to delete the arrays (i.e. individual rows) first, and then the row-pointer.
for(int index = 0; index < buff_height; ++index)
delete []stor_buff[index]; // NOTICE the syntax
delete []stor_buff;
Or, you may have a single-dimensional array, use it as 2D. For this you need to do (row,col) calculation to get the desired element.
You may also use vector (or vector of vector), to get the same. But I suggest you to play with native pointers, unless you get accustomed with pointers!