Dynamic Memory allocation in 2-D Array - c++

I have to create dynamic 2d array.I was trying with the code mentioned below:
Suppose a=512 and b =102.So Now the 2-D Array created is ary[512][102].
Now I am Creating a pointer to base location i.e int *ptr=&(ary[0][0]);
Now, if I am giving pointer the offset 102 i.e ptr+=102, it should point to &(ary[1][0]) but it doesn't point to.
If given offset of 104 then only it points to &(ary[1][0]). Why it requires extra 2 Offset????
Code Snippet:
int** ary;
ary= new int*[a];
for(int i = 0; i < a; ++i)
ary[i] = new int[b];

your 2d array is dynamically allocated as your code suggested, so the address of this 2d arrays is not in sequence, thus &(ary[0][0])+102, you can't grantee the pointer returned is the next row. So in this case, you should just use &(ary[1][0])

Unlike in the static allocation of 2D arrays, the addresses are not consecutive for the whole array when you use multiple new. Instead when you call for new() to create rows of a 2D array each new returns completely unrelated addresses which are allocated from heap. So you have to use ary[n] to access elements of (n + 1)th row and ary[n+1] to access elements of (n+2)th row and so on.

In this case, your 2-D array is not necessarily linear in the actual memory. So you can not write a program assumming that the memory is linear.
The reason for 104 pointing to ary[1][0] could be the boundary alignment. The run time system chooses to use 104 bytes for your ary[i], rather than 102.

Related

2D arrays with contiguous rows on the heap memory for cudaMemCpy2D()

CUDA documentation recommends the use of cudaMemCpy2D() for 2D arrays (and similarly cudaMemCpy3D() for 3D arrays) instead of cudaMemCpy() for better performance as the former allocates device memory more appropriately. On the other hand, all cudaMemCpy functions, just like memcpy(), require contiguous allocation of memory.
This is all fine if I create my (host) array as, for example, float myArray[h][w];. However, it most likely will not work if I use something like:
float** myArray2 = new float*[h];
for( int i = 0 ; i < h ; i++ ){
myArray2[i] = new float[w];
}
This is not a big problem except when one is trying to implement CUDA into an existing project, which is the problem I am facing. Right now, I create a temporary 1D array, copy the contents of my 2D array into it and use cudaMemCpy() and repeat the whole process to get the results after the kernel launch, but this does not seem an elegant/efficient way.
Is there a better way to handle this situation? Specifically, is there a way to create a genuine 2D array on the heap with contiguously allocated rows so that I can use cudaMemCpy2D()?
P.S: I couldn't find the answer to this question the following previous similar posts:
Allocate 2D array with cudaMallocPitch and copying with
cudaMemcpy2D
Assigning memory for contiguous 2D array
Dynamic 2d Array non contiguous memory c++ (The second answer in
this one is rather puzzling.)
Allocate the big array, then use pointer arithmetic to find the actual beginnings of the rows.
float* bigArray = new float[h * w]
float** myArray2 = new float*[h]
for( int i = 0 ; i < h ; i++ ){
myArray2[i] = &bigArray[i * w];
}
Your myArray2 array of pointers gives you C/C++ style two dimensional arrays behavior, bigArray gives you the contiguous block of memory needed by CUDA.

How to create a pointer to pointers

The problem that I have is to create a specific matrix.
I have to use an array called for example ptr with x pointers. Each pointer in this array should point to a new array (in this case, an int array; each array is a new line in the matrix then).
All x arrays should be created with new; in the end, it should be possible to access the matrix with ptr[a][b] easily.
After a lot of trying and failing, I hope that someone can help me out.
Thank you in advance!
Since this is obviously homework, let me give you a better answer for your sake to go alongside the accepted one.
std::vector<std::vector<int>> matrix(10, std::vector<int>(10));
// ^ ^ ^
// Column count ______| |________________|
// |
// |___ Each column is
// initialized with
// a vector of size 10.
That's a 10x10 matrix. Since we're using vectors, the sizes are dynamic. For statically sized arrays, you can use std::array if you want. Also, here's the reference for std::vector.
If the number of pointers in the array is known, you could simply use a raw array of pointers to int:
int* my_array[10]; // 10 int*
Then you should allocate memory individually for each pointer in the array using usually a for loop:
for(int i=0; i<10; i++){
// each int* in the array will point to an area equivalent to 10 * sizeof(int)
my_array[i] = new int[10];
}
On the other hand, if you don't know the size of the array, then you need a pointer to pointers:
int** ptr_to_ptr = new int*[10];
Note that I am allocating space for 10 int* and not int.
Remember to deallocate the memory allocated above also for the internal pointers, once you don't need that memory anymore.

When allocating a dynamic array, are the previous elements deleted?

Title says it all more or less. When I need an (for the sake of this example) integer array for an unknown amount of values I know I can change it's size using new *array = new int[size]. Now my question is: If I have an array of a certain size, but I need to make it bigger, can I just use the new operator to expand it and will it still have all previously stored elements or would it be smarter to create a whole new array with a dynamic size, copy all elements from the previous array into the new one and delete[] the old array. Basically just swapping between the two arrays, whenever I need a new size.
Specifically I am asking whether or not this piece of code would work in the way it's intended to work
for(int i = 1; i < 10; i++){
int *array = new int[i];
array[i-1] = i;
}
My assumption is that this array will first be the size of 1 and store the value 1 at index 0. Then it will reallocate its size to 2 and store the value to at index 1 and so on until i is 9.
I guess to rephrase my question a bit better: Does an array initialized with new have to be populated with elements or will it copy the elements it had from before using the operator?
You can't resize the array in this way. You need to make a new array and then copy the old array into it. You can also try std::vector, which does what you want automatically.
If you want to use pointers rather than std::vector to change the size of your array, you can do it in this way.
int n = 100; // This will be the number of elements.
int *array1; // Pointer
array1 = new int[n]; // This will allocate your array with size n, so you will have 100 elements. You can combine this with the previous in int *array1 = new int[n];
So fill up the this array however you please...
Then you decide you want a 200 element array instead? You will need to create a different array in the same way.
int *array2 = new int[200];
You can use the for loop to copy array 1 into array 2. The for loop should iterate as many times as there are elements in array 1 (100).
for(int i = 0; i < 100; ++i)
array2[i] = array[1];
At this stage array2 is exactly the same as array1, but with 100 uninitialized elements at your disposal from [100] to [199].
You won't need array1 anymore, so at some point, you should call
delete [] array1;
Your assumption, by the way would not work, because on the first cycle of your loop, you create (or try to create) an array of i=1 element. Arrays start counting at 0, so your only single element is [0]. When i is at 0, what is i-1?
If you try to access array[-1], you'll probably crash. But why should you want to create 10 different arrays? new keyword creates an unrelated object, not overwrites the one with the same name.
Does an array initialized with new have to be populated with elements or will it copy the elements it had from before using the operator?
new[] allocates new array, completely independent from previous.
I know 3 ways to "make the array bigger":
As #ravi mentioned, don't mess with poinsters, use modern std::vector.
Make new array in new pointer, std::move elements from old array to the new one, and then delete[] old array.
Get rid of new[] & delete[], use old realloc with malloc & free.
You have to allocate new array and copy old array's data into that. This is how vector is implemented. Had there been better way of doing it, C++ standard community would have considered that.

Can I access elements of a 2D array using pointers in C++?

For 1D array, I can use array name as a pointer and add offset to it to access each element of the array. Is there something similar for 2D arrays?
I defined a 2D array as follows
int arr[2][3] = {{1,2,3}, {4,5,6}};
int** arrPtr = arr;
but I got compiler error for the second line. Shouldn't 2D array have type int**?
I came across another thread here:
C++ Accessing Values at pointer of 2D Array
and saw this:
2dArray = new int*[size];
Could someone please tell me what int*[size] means? (size is an int, I presume).
Thanks a lot.
A multidimensional array defined as yours is is only a single pointer, because the data is encoded in sequence. Therefore, you can do the following:
int arr[2][3]={{1,2,3},{4,5,6}};
int* arrPtr = (int*)arr;
In general, the pointer to the element at arr[a][b] can be accessed by arrPtr + a*bSize + b where bSize is the size of the first array dimension (in this case three).
Your second question relates to dynamic memory allocation - allocating memory at runtime, instead of defining a fixed amount when the program starts. I recommend reviewing dynamic memory allocation on cplusplus.com before working with dynamically allocated 2D arrays.
int* array[10] means an array of 10 pointers to integer.
You can access a 2D array with a simple pointer to its first entry and do some maths exploiting the spacial location principle.
int array[2][2] = {{1,2}, {3, 4}};
int* p = &array[0][0];
for(int i=0; i<2*2; i++)
printf("%d ", *(p++));
If you have a matrix:
1 2
3 4
in memory it is encoded as 1 2 3 4 sequentially ;)

Flattening a 3D array in c++ for use with MPI

Can anyone help with the general format for flattening a 3D array using MPI? I think I can get the array 1 dimensional just by using (i+xlength*j+xlength*ylength*k), but then I have trouble using equations that reference particular cells of the array.
I tried chunking the code into chunks based on how many processors I had, but then when I needed a value that another processor had, I had a hard time. Is there a way to make this easier (and more efficient) using ghost cells or pointer juggling?
You have two options at least. The simpler one is to declare a preprocessor macro that hides the complexity of the index calculation, e.g.:
#define ARR(A,i,j,k) A[(i)*ylength*zlength+(j)*zlength+(k)]
ARR(myarray,i,j,k) = ARR(myarray,i+1,j,k) + ARR(myarray,i,j+1,k) + ...
This is clumsy since the macro will only work with arrays of fixed leading dimensions, e.g. whatever x ylength x zlength.
Much better way to do it is to use so-called dope vectors. Dope vectors are basically indices into the big array. You allocate one big flat chunk of size xlength * ylength * zlength to hold the actual data and then create an index vector (actually a tree in the 3D case). In your case the index has two levels:
top level, consisting of xlength pointers to the
second level, consisting of xlength arrays of pointers, each containing ylength pointers to the beginning of a block of zlength elements in memory.
Let's call the top level pointer array A. Then A[i] is a pointer to a pointer array that describes the i-th slab of data. A[i][j] is the j-th element of the i-th pointer array, which points to data[i][j][0] (if data was a 3D array). Construction of the dope vector works similar to this:
double *data = new double[xlength*ylength*zlength];
double ***A;
A = new double**[xlength];
for (int i = 0; i < xlength; i++)
{
A[i] = new double*[ylength];
for (int j = 0; j < ylength; j++)
A[i][j] = data + i*ylength*zlength + j*zlength;
}
Dope vectors are as easy to use as normal arrays with some special considerations. For example, A[i][j][k] will give you access to the desired element of data. One caveat of dope vectors is that the top level consist of pointers to other pointer tables and not of pointers to the data itself, hence A cannot be used as shortcut for &A[0][0][0], nor A[i] used as shortcut for &A[i][0][0]. Still A[i][j] is equivalent to &A[i][j][0]. Another caveat is that this form of array indexing is slower than normal 3D array indexing since it involves pointer chasing.
Some people tend to allocate a single storage block for both data and dope vectors. They simply place the index at the beginning of the allocated block and the actual data goes after that. The advantage of this method is that disposing the array is as simple as deleting the whole memory block, while disposing dope vectors, created with the code from the previous section, requires multiple invocations of the free operator.