c++ multidimensional array layout on stack and on heap - c++

on stack:
string array3d1[x][y][z];
as far as I know, internally on the stack it's actually a one dimensional array.
on heap:
string * * * array3d2;
array3d2 = new string * * [x];
for (int i = 0; i < x; i++)
{
array3d2[i] = new string * [y];
for (int j = 0; j < y; j++)
{
array3d2[i][j] = new string [z];
}
}
on heap it's array of array of array.
Questions:
(1) what's the index of array3d1[a][b][c] ?
(2) when I use below syntax to access array3d1 and array3d2:
array3d1[a][b][c];
and
array3d2[a][b][c];
how does the compiler know the right element to access since they are in different layout?

what's the index of array3d1[a][b][c]?
If you mean what is the value of &array3d1[a][b][c] - (string*)array3d1, it's equal to a*y*z + b*z + c.
how does the compiler know the right element to access since they are in different layout?
The compiler knows, because array3d1 and array3d2 have different types.
array3d1 has type array of size x of arrays of size y of arrays of size z of string, so array3d1[a] has the type array of size y of arrays of size z of string and is located at ath index of original array, that is a*y*z string*s from its beginning. And so on other indices are applied.
array3d2 has type pointer to pointer to pointer to string, and indexing is done accordingly.

Related

C++ changing multi-Dimension Array to one-D array by memory address

I read in C++ book, that
"Even though C++ enables us to model multidimensional arrays, the memory where the array is contained is one-dimensional. So the compiler maps the multidimensional array into the memory space, which expands only one direction."
And I thought, if I want to change n-dimension Array to 1-dimension Array(in order of Ascending) why just I call n-d array memory address(which is stored in 1-d format) and just put into new 1-d Array??
(usually I used for statement to change n-d array into 1-d array)
Is it possible?? and if it possible it would be thankful to provide simple example code.
A pointer to the first item in the array is also a pointer to the complete array considered as a one-dimensional array. The guarantee that the items are stored contiguously in memory comes from the sizeof requirements, that the size of an array of n items is n times the size of the item, also when the item is itself an array.
Yes, it is possible to convert an n-dimensional array to 1-d array.
Let me show by taking an example of 2-d array:
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
b[i * n + j] = a[i][j];
}
}

c++ 2D array allocation

Could someone please explain what each line is really doing here. I know overall it allocates 4 spaces, but I don't understand the details.
int** arrayArray;
arrayArray= new int*[4];
for (int x = 0; x < 4; ++x)
{ arrayArray[x] = new int[4];}
Your array is a 2D array, so it size is in forms of "x by y". The total ints your array contains will be x*y. I will call x as the row number and y as the column number.
It seems like you need a array with total 4 ints, so your row number and column number should have a product of 4, for example 2x2. Keep in mind that the following answer is dealing with a 4x4 array, which has 16 total ints.
Allocation:
int** arrayArray;
This line decelar a variable arrayArray, which is a pointer of ( pointer of int ). Like
(arrayArray) -> * -> int
So arrayArray[0] gives you a pointer of int, and arrayArray[0][0] therefore give you an int (which is in the array).
arrayArray = new int*[4];
This line allocate a space that can contain 4 pointers of int, and set the arrayArray to point to that space (don't forget that arrayArray is a pointer of a pointer of int. ).
Here the 4 means row number.
for (int x = 0; x < 4; ++x)
arrayArray[x] = new int[4];
For every pointer in arrayArray, set it to point to a space for 4 ints.
Here the 4 in new int[4] means column number.
So the structure of this array will be something like
Deallocation (free):
Notice that arrayArray by it self is just a pointer to 4 other pointer. If you want to free the entire array, you don't just free the space for the 4 pointers. You need to free every space these pointer points to, else you will cause memory leak. For example you want to free the entire array, it is just the reverse of allocation, first free all the space arrayArray points to:
for (int x = 0; x < 4; ++x)
delete[] arrayArray[x];
In C++, if you want to delete a space allocated by new something[], you need delete[] instead of delete.
Then free the array itself:
delete[] arrayArray;
int** arrayArray;
arrayArray= new int*[4];
The above code initializes 4 locations that can hold pointers to 4 int*
The next couple of lines allocate 4 int spaces for each int*, so a total of 4*4=16 integer spaces.
for (int x = 0; x < 4; ++x)
{ arrayArray[x] = new int[4];}
Now as per your comment, you want only 4 integer spaces. So that means your 2d array would be 2x2.
So your code should look something like:
int** arrayArray;
arrayArray= new int*[2];
for (int x = 0; x < 2; ++x)
{ arrayArray[x] = new int[2];}
This way you will only allocate 2 int* locations and 2 int spaces that they can point to.

I don't understand how to create and use dynamic arrays in C++

Okay so I have;
int grid_x = 5
int * grid;
grid = new int[grid_x];
*grid = 34;
cout << grid[0];
Should line 3 create an array with 5 elements? Or fill the first element with the number 5?
Line 4 fills the first element, how do I fill the rest?
Without line 4, line 5 reads "-842150451".
I don't understand what is going on, I'm trying to create a 2 dimensional array using x and y values specified by the user, and then fill each element one by one with numeric values also specified by the user. My above code was an attempt to try it out with a 1 dimensional array first.
The default C++ way of creating a dynamic(ally resizable) array of int is:
std::vector<int> grid;
Don't play around with unsafe pointers and manual dynamic allocation when the standard library already encapsulates this for you.
To create a vector of 5 elements, do this:
std::vector<int> grid(5);
You can then access its individual elements using []:
grid[0] = 34;
grid[1] = 42;
You can add new elements to the back:
// grid.size() is 5
grid.push_back(-42);
// grid.size() now returns 6
Consult reference docs to see all operations available on std::vector.
Should line 3 create an array with 5 elements?
Yes. It won't initialise them though, which is why you see a weird value.
Or fill the first element with the number 5?
new int(grid_x), with round brackets, would create a single object, not an array, and specify the initial value.
There's no way to allocate an array with new and initialise them with a (non-zero) value. You'll have to assign the values after allocation.
Line 4 fills the first element, how do I fill the rest?
You can use the subscript operator [] to access elements:
grid[0] = 34; // Equivalent to: *(grid) = 34
grid[1] = 42; // Equivalent to: *(grid+1) = 42
// ...
grid[4] = 77; // That's the last one: 5 elements from 0 to 4.
However, you usually don't want to juggle raw pointers like this; the burden of having to delete[] the array when you've finished with it can be difficult to fulfill. Instead, use the standard library. Here's one way to make a two-dimensional grid:
#include <vector>
std::vector<std::vector<int>> grid(grid_x, std::vector<int>(grid_y));
grid[x][y] = 42; // for any x is between 0 and grid_x-1, y between 0 and grid_y-1
Or might be more efficient to use a single contiguous array; you'll need your own little functions to access that as a two-dimenionsal grid. Something like this might be a good starting point:
template <typename T>
class Grid {
public:
Grid(size_t x, size_t y) : size_x(x), size_y(y), v(x*y) {}
T & operator()(size_t x, size_t y) {return v[y*size_x + x];}
T const & operator()(size_t x, size_t y) const {return v[y*size_x + x];}
private:
size_t size_x, size_y;
std::vector<T> v;
};
Grid grid(grid_x,grid_y);
grid(x,y) = 42;
Should line 3 create an array with 5 elements? Or fill the first element with the number 5?
Create an array with 5 elements.
Line 4 fills the first element, how do I fill the rest?
grid[n] = x;
Where n is the index of the element you want to set and x is the value.
Line 3 allocates memory for 5 integers side by side in memory so that they can be accessed and modified by...
The bracket operator, x[y] is exactly equivalent to *(x+y), so you could change Line 4 to grid[0] = 34; to make it more readable (this is why grid[2] will do the same thing as 2[grid]!)
An array is simply a contiguous block of memory. Therefore it has a starting address.
int * grid;
Is the C representation of the address of an integer, you can read the * as 'pointer'. Since your array is an array of integers, the address of the first element in the array is effectively the same as the address of the array. Hence line 3
grid = new int[grid_x];
allocates enough memory (on the heap) to hold the array and places its address in the grid variable. At this point the content of that memory is whatever it was when the physical silicon was last used. Reading from uninitialised memory will result in unpredictable values, hence your observation that leaving out line 4 results in strange output.
Remember that * pointer? On line four you can read it as 'the content of the pointer' and therefore
*grid = 34;
means set the content of the memory pointed to by grid to the value 34. But line 3 gave grid the address of the first element of the array. So line 4 sets the first element of the array to be 34.
In C, arrays use a zero-based index, which means that the first element of the array is number 0 and the last is number-of-elements-in-the-array - 1. So one way of filling the array is to index each element in turn to set a value to it.
for(int index = 0; index < grid_x; index++)
{
grid[index] = 34;
}
Alternatively, you could continue to use a pointer to do the same job.
for(int* pointerToElement = grid; 0 < grid_x; grid_x-- )
{
// save 34 to the address held by the pointer
/// and post-increment the pointer to the next element.
*pointerToElement++ = 34;
}
Have fun with arrays and pointers, they consistently provide a huge range of opportunities to spend sleepless hours wondering why your code doesn't work, PC reboots, router catches fire, etc, etc.
int grid_x = 5
int * grid;
grid = new int[grid_x];
*grid = 34;
cout << grid[0];
Should line 3 create an array with 5 elements? Or fill the first
element with the number 5?
Definitely the former. With the operator "new" you are allocating memory
Line 4 fills the first element, how do I fill the rest?
Use operator [], e.g.:
for int (i=0; i < grid_x; i++) { //Reset the buffer
grid[i] = 0;
}
Without line 4, line 5 reads "-842150451".
You are just reading uninitialized memory, it could be any value.
I don't understand what is going on, I'm trying to create a 2
dimensional array using x and y values specified by the user, and then
fill each element one by one with numeric values also specified by the
user. My above code was an attempt to try it out with a 1 dimensional
array first.
Other users explained how to use vectors. If you have to set only once the size of your array, I usually prefer boost::scoped_array which takes care of deleting when the variable goes out of scope.
For a two dimensional array of size not known at compile time, you need something a little bit trickier, like a scoped_array of scoped_arrays. Creating it will require necessarily a for loop, though.
using boost::scoped_array;
int grid_x;
int grid_y;
///Reading values from user...
scoped_array<scoped_array<int> > grid(new scoped_array<int> [grid_x]);
for (int i = 0; i < grid_x; i++)
grid[i] = scoped_array<int>(new int[grid_y] );
You will be able then to access your grid elements as
grid[x][y];
Note:
It would work also taking scoped_array out of the game,
typedef int* p_int_t;
p_int_t* grid = new p_int_t [grid_x];
for (int i = 0; i < grid_x; i++)
grid[i] = new int[grid_y];
but then you would have to take care of deletion at the end of the array's life, of ALL sub arrays.

Writing MATLAB arrays in C/C++

The MATLAB code samples part of background of an grayscale image by creating a cell array that is backgroundSample{1}, backgroundSample{2}, ... , backgroundSample{9}. Here halfRows and halfCols is the half size of the image.
Since backgroundSample is an array that contains nine 2-D matrices. It confused me that how to write this code in C/C++. Can I get the elements of backgroundSample{i} using something like backgroundSample[i].elements[m][n]?
MATLAB code:
offset = [-60, -20, 20, 60];
for i = 1: 1: 3
for j = 1: 1: 3
backgroundSample{(i - 1) * 3 + j} =
background(halfRows + offset(i): halfRows + offset(i + 1), ...
halfCols + offset(j): halfCols + offset(j + 1));
end;
end;
EDIT:
As we can assign a matrix simply by A = B in MATLAB. For an example, backgroundSample{1} = background(60: 100, 60: 100) in my question and this assignment is in the loops of i: 1→3 and j: 1→3. However, when assigning a matrix in C/C++, it should assign every element one by one. Maybe like this:
for(int i = 0; i < 3; i++)
for(int j = 0; n < 3; j++)
// to get every elements
for(int m = 0 ...)
for(int n = 0 ...)
// not sure whether there is such usage of "->" in array
backgroundSample[(i - 1) * 3 + j]->elements[m][n] = background[i iteration][j iteration]
So there are conflicts between indices of matrix backgroundSample[m][n] and background[i][j]. How to resolve the issue?
The simplest way to implement what you're describing is to declare a multidimensional array:
int backgroundSample[9][3][3];
where the dimensions of each 2-D matrix is assumed to be 3×3. To access the (m, n) element in the k-th matrix, you write backgroundSample[k][m][n], e.g:
for (int m = 0; m < 3; ++m)
{
for(int n = 0; n < 3; ++n)
{
backgroundSample[(i - 1) * 3 + j][m][n] = background[i][j];
}
}
Alternatively, if each sample in this array stores more information, you can declare a structure:
typedef struct
{
int elements[3][3];
// More fields...
} TSample;
and then create an array of these:
TSample backgroundSample[9];
To access an element you would write backgroundSample[k].elements[m][n].
There's also the possibility of allocating the memory dynamically (during runtime, meaning that you don't know how much of these structures you have in advance):
TSample* backgroundSample;
In C++ the actual process of memory allocation would look like this:
backgroundSample = new TSample[9];
Accessing an element would be done by writing backgroundSample[k]->elements[m][n]. Notice the array operator -> which accesses the field elements by dereferencing the pointer backgroundSample[k].
Note: each call to new needs to be accompanied by a matching call to delete when done in order to release the memory, i.e:
delete[] backgroundSample;
Hope that helps!

Two dimensional array, what does *(pointerArray[i] + j)?

i just got this task of finding out how this code works.
int array[rows][coloums];
int *pointerArray[rows];
for (int i = 0; i < rows; i++) {
pointerArray[i] = array[i];
for (int j = 0; j < coloums; j++) {
*(pointerArray[i] + j) = 0;
}
}
The thing I'm courious about is the *(pointerArray[i] + j), I think it's the same thing as pointerArray[i][j], since you can access the element both ways, But can anyone tell me what is actually happening with the *()? Like how does the compiler know that im asking for the same as pointerArray[i][j]?
Thanks for the answers!
When you do pointerArray[i] + j, you request the element pointerArray[i], which is a int*, and increment that pointer by j (also returning an int*). The *(...) simply dereferences the pointer and returns the int at that position. * is called the dereference operator (in this case). So yes, it's equivalent to pointerArray[i][j].
In this context, the * operator is the dereference operator. The value it prepends will be the location in memory at which it will return a value.
The parenthesis are grouping an addition operation so that the compiler knows that the result of this addition will be used for the dereference. It's simply a case of order-of-operations.
Keep in mind that the [] operator does the same thing as the dereference operator, because arrays are essentially a kind of pointer variable. If you imagine a two-dimensional array as a 2D grid of values with rows and columns, in memory the data is laid out such that each row is strung one after the next in sequential order. The first index in the array (i) along with the type of the array (int) tells the compiler at what offset to look for the first location in the row. The second index in the array (j) tells it at what offset within that row to look.
*(pointerArray[i] + j) basically means: "Find the beginning of the ith row of data in pointerArray, and then pick the jth element of that row, and give me that value.