I am studying c++ and found this in the book
array_ptr = new int[3][5][4];
This is used to allocate memory to a multi dimensional array using new. It also states while first dimension can be a variable whose value is supplied at runtime, others must be constant.
I tried to run this code
int *p = new int[3][5][6];
But it is showing an error.
Can someone elaborate.
Here is what you want:
int (*p)[5][6] = new int[3][5][6];
Since C++11 you can ask the compiler to decuce the type of p for you:
auto p = new int[3][5][6];
You don't need anything special to delete such array:
delete [] p;
Logic behind the choice of the type is simple:
In this line: int *p = new int[10] you're creating an array of 10 ints and you use pointer to int to store the address.
In general case, if you're allocating an array of N Ts (where N is the size and T is the type), you use pointer to T to store the address.
Same rule can be applied to multidimensional arrays, because they are in fact nested 1D arrays.
When you try to allocate multidimensional array: p = new int[4][5][6], you're creating an array of 4 arrays of 5 arrays of 6 ints. Thus you need a pointer to array of 5 arrays of 6 ints, which is int (*p)[5][6].
In other words, int [3][4][5] can be viewed as 1D array of size 3. It consists of other arrays of type int [4][5]. Each of these arrays has size 4 and consists of other arrays of type int [5], which in turn contain 5 ints.
P.S. Authors of other answers seem to favor using int *** and allocating memory for each nested array separately. Doing so may seem smart, but in fact it's much slower and dangerous (if you mess up your memory management). The only advantage of that trick is that it provides the convenient interface we all used to (p[z][y][x]).
But there is a much better solution: int *p = new int[x_sz * y_sz * z_sz];. You would need to convert 3D indices to 1D index (p[x + x_sz * (y + z * y_sz)] instead of p[z][y][x]) for it to work, but in my opinion it's still more convenient (and definitely faster).
Of course, in real code, you should use std::vector to store such array and write your own wrapper class, which would compute the index automatically.
A 3d array is not the same as a pointer to int, and you can't make them the same.
If you need dynamic allocation, you can use special class std::vector (best choose), std::array, or write next code:
int ***p = new int**[3];
for (int i = 0; i < 3; ++i) {
p[i] = new int*[5];
for (int j = 0; j < 5; ++j) {
p[i][j] = new int[6];
}
}
In order to create dynamic 3d array you have to use pointer to pointer to pointer)
const int xSize = 3;
const int ySize = 5;
const int zSize = 4;
int*** p = nullptr;
// creating array of pointers to pointers
p = new int** [xSize]
// for each pointer to pointers, create array of pointers
for( int i = 0; i < xSize; ++i )
p[ i ] = new int* [ySize];
// now we have 2d array of pointers, for each of them allocate array
for( int i = 0; i < xSize; ++i )
for( int j = 0; j < ySize; ++j )
p[ i ][ j ] = new int [zSize];
But is much more better to use vectors
vector<vector<vector<int> > > v3d;
v3d.resize( 3 );
for( int i = 0; i < xSize; ++i )
v3d[ i ].resize( ySize );
for( int i = 0; i < xSize; ++i )
for( int j = 0; j < ySize; ++j )
v3d[ i ][ j ].resize( zSize );
Related
hey I want to allocate some memory for a 2D array and free it later in C++
I want to do this as I am getting an Error in my program " EXPRESSION MUST HAVE A CONSTANT VALUE.
int x = height;
int y = width;
int pixelArray[x][y];
Thank you.
I'm using Visual Studio 2013
The naive approach is to allocate one array to contain row pointers, and then allocate every single row, but this can lead to poor performance of your array due to memory locality. It also cannot be used in the same way as a fixed-size 2D array, which is contiguous in memory.
So what you can do is allocate one block of integers to hold all the data, and one array of pointers to index it.
int ** my_array = new int*[ x ];
my_array[0] = new int[ x * y ];
for( int i = 1; i < x; i++ )
{
my_array[i] = my_array[i-1] + y;
}
To clean up, you do this:
delete [] my_array[0];
delete [] my_array;
You should consider wrapping this functionality into a simple class, since it is maintaining more than one pointer.
Since x and y are variables, you have to dynamically allocate the array using new. You can initialize a 2D array as follows:
int ** pixelArray = new int*[x];
for (int i = 0; i < x; i++) {
pixelArray[i] = new int[y];
}
And you dispose of it in the following way:
for (int i = 0; i < x; i++) {
delete[] pixelArray[i];
}
delete[] pixelArray;
I'm trying to convert the a 1D array to a 2D array
If you want to allocate an actual 2D array, not an array of pointers, the syntax gets a little tricky:
int X = 16, Y = 8;
char (*pt)[X][Y] = malloc(X*Y);
Above, pt is a pointer to an X by Y array of chars. Because it's a pointer, accessing its elements requires an asterisk and parentheses, too:
for (int i = 0 ; i != X ; i++) {
for (int j = 0 ; j != Y ; j++) {
(*pt)[i][j] = (char)(i*X+j);
}
}
Of course you need to free the pointer once you are done using the array:
free(pt);
You need to allocate each row of the matrix separately:
unsigned char** index;
index = malloc(X * sizeof(unsigned char*)); // Allocate an array of pointers
for(int i = 0; i < X; i++)
index[i] = malloc(Y * sizeof(unsigned char)) // Allocate each row
Refer also to this answer on malloc pointer casting.
unsigned char **index;
index = (unsigned char**)malloc( X*Y );
is wrong. index is an unsigned char**. You need to malloc two times to get a 2D array. If you want to allocate X rows, each with Y columns, use
unsigned char **index;
index = (unsigned char**)malloc( X * sizeof(unsigned char*) ); //Allocating number of rows
for(int i=0 ; i<X ; i++ )
{
index[i] = (unsigned char*)malloc( Y * sizeof(unsigned char)); // Allocate each column
}
You should check if malloc does not fail. You should also free everything after its use to avoid a memory leak.
After your edit, it appears you are using C++.
In C++, you should prefer std::vector< std::vector< unsigned char > > for dynamic 2d array.
std::vector< std::vector< unsigned char > > index(X, std::vector<unsigned char>(Y));
Now you can use it as index[i][j] and it will be automatically cleaned, so need to free/delete explicitly.
Live demo here
Still if you want to allocate c-compliant arrays in conventional way, use
unsigned char** index;
try {
index = new int*[X];
for(int i = 0; i < X; ++i)
index[i] = new int[Y];
} catch(...) {...}
For delete also you need to delete each element individually.
Old answer
unsigned char **index;
index = malloc(X * sizeof *index);
if(!index) fail();
for(xi = 0; xi < X; ++xi) {
index[xi] = malloc(Y * sizeof **index);
if(!index[xi]) free_and_fail();
}
You first allocate space for X pointers and then in all X pointers you allocate one array.
While freeing the memory, you need to free each row individually:
if(index) for(xi = Y-1; xi >= 0; --xi) { /* xi is signed */
free(index[xi];
}
free(index);
index = NULL;
I need to create a square matrix of a given size. I know how to create a dynamic one-dimensional array of a given size. Doesn't the same work for two dimensinal arrays like the lines below?
cin>>size;
int* a[][]=new int[size][size]
int* a[][]=new int[size][size]
No, this doesn't work.
main.cpp:4: error: only the first dimension of an allocated array may have dynamic size
new int[size][size];
^~~~
If the size of the rows were fixed then you could do:
// allocate an array with `size` rows and 10 columns
int (*array)[10] = new int[size][10];
In C++ you can't have raw arrays with two dimensions where both dimensions are dynamic. This is because raw array indexing works in terms of pointers; for example, in order to access the second row a pointer to the first needs to be incremented by the size of the row. But when the size of a row is dynamic the array doesn't know that size and so C++ doesn't know how to figure out how to do the pointer increment.
If you want an array with multiple dynamic dimensions, then you need to either structure the array allocations such that C++'s default array indexing logic can handle it (such as the top answers to this duplicate question), or you need to implement the logic for figuring out the appropriate pointer increments yourself.
For an array where each row has the same size I would recommend against using multiple allocations such as those answers suggest, or using a vector of vectors. Using a vector of vectors addresses the difficulty and dangerousness of doing the allocations by hand, but it still uses more memory than necessary and doesn't allow faster memory access patterns.
A different approach, flattening the multi-dimensional array, can make for code as easy to read and write as any other approach, doesn't use extra memory, and can perform much, much better.
A flattened array means you use just a single dimentional array that has the same number of elements as your desired 2D array, and you perform arithmetic for converting between the multi-dimensional indices and the corresponding single dimensional index. With new it looks like:
int *arr = new int[row_count * column_count];
Row i, column j in the 2d array corresponds to arr[column_count*i + j]. arr[n] corresponds to the element at row n/column_count and column n% column_count. For example, in an array with 10 columns, row 0 column 0 corresponds to arr[0]; row 0, column 1 correponds to arr[1]; row 1 column 0 correponds to arr[10]; row 1, column 1 corresponds to arr[11].
You should avoid doing manual memory management using raw new and delete, such as in the case of int *arr = new int[size];. Instead resource management should be wrapped up inside a RAII class. One example of a RAII class for managing dynamically allocated memory is std::vector.
std::vector<int> arr(row_count * column_count);
arr[column_count*i + j]
You can further wrap the logic for computing indices up in another class:
#include <vector>
class Array2d {
std::vector<int> arr;
int columns;
public:
Array2d(int rows, int columns)
: arr(rows * columns)
, columns(columns)
{}
struct Array2dindex { int row; int column; };
int &operator[] (Array2dindex i) {
return arr[columns*i.row + i.column];
}
};
#include <iostream>
int main() {
int size;
std::cin >> size;
Array2d arr(size, size);
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
arr[{i, j}] = 100;
}
}
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
std::cout << arr[{i, j}] << ' ';
}
std::cout << '\n';
}
}
If you're using C++11 you can also use std::array.
const int iRows = 3, iCols = 3; // number of rows and columns
std::array<std::array<int, iCols>, iRows> matrix;
// fill with 1,2,3 4,5,6 7,8,9
for(int i=0;i<iRows;++i)
for(int j=0;j<iCols;++j)
matrix[i][j] = i * iCols + j + 1;
This class also allows for bounds checking by using the function
std::array::at
which (just like operator[]) returns a const reference if the array-object is const-qualified or a reference if it is not. Please note that
std::array
is not a variable-sized array-type, like
std::vector
You can use std::vector:
std::vector<std::vector<int*>> a(size, std::vector<int*>(size));
This will create a dynamically allocated 2D array of int* with width and height equal to size.
Or the same with new:
int*** a = new int**[size];
for (size_t i = 0; i < size; ++i)
a[i] = new int*[size];
...
for (size_t i = 0; i < size; ++i)
delete a[i];
delete a;
Note that there's no new[][] operator in C++, you just have to call new[] twice.
However, if you want to do it with new and delete instead of std::vector, you should use smart pointers instead of raw pointers, for example:
std::unique_ptr<std::unique_ptr<int*>[]> a(new std::unique_ptr<int*>[size]);
for (size_t i = 0; i < size; ++i)
a[i].reset(new int*[size]);
...
// No need to call `delete`, std::unique_ptr does it automatically.
I had been trying to allocate dynamic memory for a two-dimensional array. After searchin a lot I've found a code that looks easier than others still I'm unable to understand each and every detail of it. Can someone explain me how does the following code assigns memory to the array dynamically. Really looking forward for help and sorry but I'm new to C++ and want to learn it.
void main()
{
int m,n;
cin>>m;
cin>>n;
//Allocate
int *a = new int[m*n];
//Use a[m][n]
for( int i = 0 ; i < m ; i++)
for ( int j = 0 ; j < n ; j++)
a[i*n + j] = 1;
}
The code just uses a single memory block to represent all elements, so to access a sample ( i, j ) it needs to calculate the index being i * num_rows + j (or num_colums depending how you look at it).
But as commented, don't use new int...., use something like
std::vector< int > a( m * n );
First of all, what you're doing, is adding 1 to different slots of a ONE-dimensional array.
Here's a commented version of your code:
int *a = new int[m*n]; // declares a pointer a, that points to a newly
// allocated space on the heap, for an array of size m*n.
for( int i = 0 ; i < m ; i++) // loop through m number of times
for ( int j = 0 ; j < n ; j++) // loop through n number of times PER m
a[i*n + j] = 1; // assigns 1 to a spot [i*n + j]
THIS is how you make a dynamic 2D array (in other words, array of pointers to arrays):
const int sizeX = 10;
const int sizeY = 5;
int** arrayOfPointers = new int*[sizeX];
for(int i = 0; i < sizeX; i++)
arrayOfPointers[i] = new int[sizeY];
Then, you can add multiple elements to that array using a double loop (NOT TESTED):
for(int i = 0 ; i < sizeY ; i++) // loop through all the rows
for (int j = 0 ; j < sizeX ; j++) // loop through all columns for row i
arrayOfPointers[i][j] = i*j; // assigns i*j to a spot at row i, column j
This is how you can print out the contents of the 2D array:
for(int i = 0 ; i < sizeY ; i++) {
for (int j = 0 ; j < sizeX ; j++)
cout << arrayOfPointers[i][j];
cout << endl; // go to the next line when the row is finished
}
First, let me point out that this is not a two-dimensional array, but rather a one-dimensional one. You can see that int* a = new int[ m*n ] allocates an array for integers of size m*n.
To obtain a two-dimensional array, you might use int** a = new int*[m]. Note the two asterisks (*) that are used here. Having allocated the "first" dimension of the array, you now have to allocate the second one via:
for( int i = 0; i < m; i++ )
{
a[i] = new int[n];
}
Afterwards, you can loop over m and n and use a[i][j] to access the array contents.
Using the STL in C++, you can obtain two-dimensional arrays by using a two-dimensional vector, like so:
std::vector< std::vector<int> > array( rows,
std::vector<int>( columns ) );
This would allocate a two-dimensional vector containing integers, with rows elements in the first dimension and columns elements in the second dimension. Such use is sometimes frowned upon, but std::vector manages memory for your, which might be nice.
Despite what Paul R said and which I fully support, the comment in the code above is wrong, you cannot use a[m][n] for proper addressing of an array that has been allocated as one dimensional memory.
what you can do, if you really must work without using C++ standard containers like vector or array is to allocate the full block and then store addresses to the start of the rows
int** createTwoDimMatrix(unsinged int rows, unsigned int columns)
{
int** rowAdressTable = new int*[rows];
int* baseMemory = new int[rows*columns];
//fill the rowAddressTable
for(unsinged int r=1; r<rows; ++r)
{
rowAdressTable[r] = rowsAdressTable[r-1]+columns*sizeof(int)
}
return rowAdressTable;
}
But let me repeat: Please, consider using C++ containers
For the memory it doesn't matter what kind of arrays you have they are all stored as one block of memory, those can the visualised as an 1d array.
In this example, since you want to cave an m x n array you alocate a block of m*n size. The difference between this way and the others is that now you have to acess your array as 1d.
For exemple having the follwoing 2d array:
1 2 3
4 5 6
7 8 9
It will be stored in the memory as follows:
1 2 3 4 5 6 7 8 9
I think you can see the pattern: in order to acces a[i][j] from your 2d array, the 1d equivalent would be a[i*dim+j] where dim is the length of your row.
The way you access your array depends solely on the way you allocate it. In order to be able to acces you elements directly as arr[i][j] you have to allocate the memory ass follows:
int **arr = new int *[n];
for (int i=0; i<n; i++)
arr[i] = new int [m];
This will create an nxm array.
Dynamic is like
int *p = new int [10][10]
then *(p+(i*noofcols)+j) gives value
CASE1:
int nrows=5;
int ncols=10;
int **rowptr;
rowptr=new int*;
for(int rows=0;rows<nrows;rows++) {
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
CASE2:
int nrows=5;
int ncols=10;
int **rowptr;
for(int rows=0;rows<nrows;rows++) {
rowptr=new int*;
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
I am able to insert and print values using both ways. What is the difference in initializations?
What is the difference?
#1 just allocates memory enough to hold a integer pointer and not an array of integer pointers.
#2 Causes a memory leak by just overwritting the memory allocation of the previous iteration.
I am able to insert and print values using both the ways
Memory leaks and Undefined behaviors may not produce immediate observale erroneous results in your program but they sure are good cases of the Murphy's Law.
The correct way to do this is:
int nrows = 5;
int ncols = 10;
//Allocate enough memory for an array of integer pointers
int **rowptr = new int*[nrows];
//loop through the array and create the second dimension
for (int i = 0;i < nrows;i++)
rowptr[i] = new int[ncols];
You have a memory leak in both cases.
The proper way to initialize such a "2d" array is
int** arr = new int*[nrows];
for (int i = 0; i < nrows; i++)
arr[i] = new int[ncols];
Note however, that it isn't a 2d array as defined by C/C++. It may not, and probably will not, be consecutive in memory. Also, the assembly code for accessing members is different.
In your case, the accessing by indexing is equivalent to *(*(arr+i)+j)
And in the case of a 2d array it's *(arr + N_COLS*i + j) when N_COLS is a compile time constant.
If you want a true 2d array you should do something like this:
int (*arr)[N_COLS] = (int(*)[N_COLS])(new int[N_ROWS * N_COLS])
You'd better use 1d array to manage 2d array
int **x = new int*[nrows];
x[0] = new int[nrows*ncols];
for (int i = 1; i < nrows; i++)
x[i] = x[i-1] + ncols;
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++)
x[i][j] = 0;
delete [] x[0];
delete [] x;