how to create multidimensional, dynamically defined array? - c++

i know how to create a single-dimensional, dynamically defined array
string *names = new string[number]; //number specified by the user
however, when i try to make it multidimensional
string *names = new string[number][number]; //doesn't work
it doesn't work. what gives? i found this http://www.cplusplus.com/forum/beginner/63/ but am completely confused by what they are saying. anyone care to explain? thanks so much.

I tried to provide some explanations to example from your link:
// To dynamically allocate two-dimensional array we will allocate array of pointers to int first.
// Each pointer will represent a row in your matrix.
// Next step we allocate enough memory for each row and assign this memory for row pointers.
const int rows = 4; //number of rows in your matrix
const int cols = 4; //number of columns in your matrix
// declaration
int ** a;
/* allocating memory for pointers to rows. Each row will be a dynamically allocated array of int */
a = new int*[rows];
/* for each row you allocate enough memory to contain cols elements. cols - number of columns*/
for(int i = 0; i < rows; i++)
a[i] = new int[cols];

The memory layout of single-dimension array (let's say with three elements) looks like,
names ------> [0] [1] [2]
And the two-dimensional array (let's say with 3 X 3 elements) would look like,
names ------> [0] --> [0] [1] [2]
[1] --> [0] [1] [2]
[2] --> [0] [1] [2]
^
|
this is an array of pointers
i.e. two dimensional array is array of pointers to arrays, therefore you would need **names in first place.
string **names = new string*[number]; // allocating space for array of string pointers
Now, you want each element of this array of string pointers to point to an array of strings.
Therefore, you would need to do
for(int i = 0; i < number, i++) {
names[i] = new string[number];
}
I hope this helps to understand it better.

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.

Trying to create a jagged array c++

int** DATA = new int*[10];
DATA[0] = new int[100]; //works
DATA[1] = new int[100][5]; //dont work
DATA[1][100] = 1;
hello, i'm trying to create a jagged array, but need 5 columns. thanks
Do you really need a jagged array (different number of columns for each row) or just a two dimensional array, with 5 columns for each row. In both cases Ulrich's advice to prefer std::vector over bare arrays is good, and you should consider it.
However if you absolutely require a two dimensional array created in C-style, the way to do it is
int** p = new int*[10];
for( int i=0; i<10; i++ ) {
p[i] = new int[20];
}
p[7][17] = 177;
This will create a 2D array with 10 rows and 20 columns that can be accessed using 2D array syntax.

c++ multidimensional array layout on stack and on heap

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.

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.