What are the different ways of declaring a 2D array in C++? - c++

There is one where you just write array[rowSize][colSize]. Another where you declare it as an array of pointers to arrays using new. (From How do I declare a 2d array in C++ using new? )
int** ary = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
ary[i] = new int[colCount];
There should be one using malloc. Are there any more? What are the pros/cons of each of them? How about their speed of execution/processing?
(This is an interview question. So, more than just suggesting the most optimal method, I need to know what each of these methods do)

I do not fully understand the question here, but I can tell you the differences between the two. When using new (or malloc) the variables stay off the stack. When declaring the variable like:
int iarray[10][10];
it uses stack space. The downside to using the new operator is that you must remember to use the delete [] operator, too.

There are different types:
1. This is an array where each element is an array itself:
int array[rowSize][colSize];
It is like this:
typedef int A[colSize];
A array[rowSize];
where sizeof(A) is colSize*sizeof(int)
and sizeof(array) is rowSize*sizeof(A)
indexes of elements in memory for a[3][3]:
|0,0|0,1|0,2|1,0|1,1|1,2|2,0|2,1|2,2|
2. This instead is a pointer to a pointer:
int** ary
where ary may refer to array of pointers
where each element may refer to any size array of int.
size of pointer is machine dependent.
It initialized in example as array of poiner. And after that each element of it is initialized newely created array.
For your example:
int** ary = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
ary[i] = new int[colCount];
have rowCount and colCount equal to 3 and 3,
than allocated arrays and indexes in memory:
|0|1|2| ... |0,0|0,1|0,2| ... |1,0|1,1|1,2| ... |2,0|2,1|2,2|
| | | ^ ^ ^
| | -------- | |
| ---------------------------- |
------------------------------------------------

Related

Didn't understand creating 2d dynamic array with double pointer (**)

I have some problems with understanding double-pointer stuff.Okay , I know, that it means "pointer to pointer". But when I see it in code I just don't get it. For example:
// Create Dynamic 2D-Array
int **arr = new int*[rows];
for (int i = 0; i < rows; i++)
{
arr[i] = new int[cols];
}
This the code that my teacher used to create 2d dynamic array, but I didn't understand. Can anyone explain? For example what int **arr = new int*[rows]; means? Or For what did we use for there?
And one more question: Is there any way to create 2d dynamic array without using pointers?
While you will see a lot of this type of code in code written from the 90s through say 2011 (and some past then). This type of collection of pointers that allows elements to be accessed using 2D array indexing has been replaced by std::vector (or a vector-of-vectors in this case).
The first thing to understand is int **arr; declares a single-pointer to pointer-to-int. (also called a double-pointer). Either way you have a single-pointer to what? (a pointer-to-type, whatever the type used is).
In order to make this approach useful, you first allocate the number of pointers you will need. The following allocates a block of memory containing rows number of pointers-to-int and assigns the address of the first pointer to arr.
int **arr = new int*[rows];
Now you have rows number of uninitialized pointers. (e.g. you have a block of memory capable of holding rows pointers). To access each pointer in arr, you simply use array-indexing (e.g. arr[2] is the 3rd pointer in the block allocated.) Equivalent pointer notation would be *(arr + 2). (note: the [..] acts as a dereference just the same as *(..) does in the pointer notation case)
To be useful, each of the pointers in the block allocated must point to valid memory holding some number of integers. You can either assign an address for an existing array of integers, e.g.
#define COLS 5
...
int myarray[COLS] = {0}; /* array of COLS integer values initialized zero */
int **arr = new int*[rows]; /* your allocation a block for rows pointers to int */
...
arr[0] = myarray; /* assigning pointer to existing block to arr[0] */
In your case, you are simply allocating a block of memory that can contain cols number of integer and assigning the starting address for that block to one of your pointers in the block you allocated with int **arr = new int*[rows];. That is what the following code does:
// Create rows pointers pointing to allocated blocks of cols integers
int **arr = new int*[rows]; /* allocated block of rows pointers */
for (int i = 0; i < rows; i++) /* for each pointer */
{
arr[i] = new int[cols]; /* allocate & assign block of cols int */
}
Now your object is complete. You have a block of memory sized so it can contain rows number of pointers, and you have allocated rows number of blocks of memory that can hold cols number of integers and have assigned the starting address for each of the blocks of memory holding cols number of integers to each of the pointers contained in the original block allocated.
Since you can access each pointer with arr[x] where 0 <= x < rows, you can access each individual integer within each block of memory simply by including another index (the simulated 2D indexing) so that arr[x][y] will address the yth integer in the block of memory pointed to by arr[x] where 0 <= y < cols. The equivalent pointer notation would be *(*(arr + x) + y).
That's it in a nutshell. You allocate storage for some number of pointers, and then allocate storage for some number of type values and assign the starting address for each of those pointers such that each of your pointers now holds the address of (e.g. points to) an allocated block of memory holding your values.
Now you must individually delete[] each of the blocks of storage for cols number of ints, (e.g. loop and delete[] arr[i];) and then make one final call to delete[] arr; to free the block of memory containing the pointers.
Think though it and let me know if you have further questions.
A couple of observations that might help you:
A pointer occupies memory in the same way any other variable does. It is similar to any other type. So, if you draw a little rectangle for the variable i, you can also draw one for a pointer.
Use typedef or using to create aliases and simplify definition of complex types:
using pointer_to_int = int*;
pointer_to_int* arr = new pointer_to_int[rows]; // allocates an array of pointer_to_int (similar to new int[rows])
for (int i = 0; i < rows; i++)
{
arr[i] = new int[cols]; // arr[i] is of type pointer_to_int
}
"Is there any way to create 2d dynamic array without using pointers?" It depends on the level you are looking at. In the end, somewhere, there will be a pointer. You may use an 1d array (vector<T>, if allowed) and divide it by rows (or columns). If the row has 3 columns, the first row starts at index 0, the second row starts at index 3, the third row starts at index 6, etc. See Dynamically create matrix from numerical input in C++
.
It creates an array of pointers, each pointer in that array points to a different place in memory
+-arr--+
| | +---------------+
| 0 | -> | ... cols |
| | +---------------+
+------+
| | +---------------+
| 1 | -> | ... cols |
| | +---------------+
+------+
...
+------+
| | +---------------+
|rows-1| -> | ... cols |
| | +---------------+
+------+
So it does not consist of consecutive memory like it would if you would declare it as
int arr[rows][cols];

Declaring a 2D array using double pointer

I am confused about this line in a C++ program. The idea of the program is to check whether a 4x4 array is symmetric or not. This part of the code declares a 2D array, which I do not understand.
int** array = new int*[n];
Although, there is another question similar to this but it is about single pointer which I get.
int *array = new int[n];
I do not understand the double pointer. Kindly explain.
How do you create a single pointer array? You do this:
int* myArray = new int[n];
What does this mean? It has two parts. First part is reserving a pointer int* we call it myArray, and the second part is that you reserve n elements, each with size int in memory (this is an array, right?), and you take the address of that array and you save it in the variable myArray.
Now you want a 2D array, which is an array of an array. So Every element of this new array of array is one of these, that we talked about up there. How do we reserve this? We do:
new int*[n];
Because we are reserving n slots, each with type int*, that we talked about before.
Now what is the type of the return value? It's an array of an array, or a "pointer to an array, and the latter is also a pointer to an array", so you write it as
(int*)*
Or
int**
so it becomes
int** array = new int*[n];
int** array is a pointer to a pointer to an int. So by doing this:
int** array = new int*[n];
you are creating a section of memory that holds n int* pointers and pointing array at that memory. For each of these pointers that you have created, it is possible to create a set of ints like so:
for (auto i = 0; i < n; ++i)
array[i] = new int[n];
The resulting memory will look like this:
array -> [ int* | int * | .... n
[int | int | ...][int | int | ...][ ... n
This is however, much much easier if you use some of the std things in c++, ie a std::vector :
std::vector<std::vector<int>> arr(std::vector<int>(0, n), n);
and you are done ...

Constant for a multi-dimensional array

I'm trying to create a multi-dimensional array, the size of which the user will supply.
So far I have this:
int definedgroups; // for number of groups needed
cout << "Enter the Number of Groups you require: " << endl;
cin >> definedgroups;
const int definedgroups = definedgroups;
int User_Groups [definedgroups] [4];
I believe the array needs constant values, so i tried assigning my variable as a constant but still no luck.
In C++, static arrays, that is, those defined like this:
foo arrayStatic[bar];
require bar to be a constant integer. In other words, the programmer needs to know its value beforehand.
Whenever bar is unknown, a dynamic array could be used instead. They're defined like this:
foo* arrayDynamic;
arrayDynamic = new foo[bar];
Here, bar could be an integer variable.
Don't forget that dynamic memory must be deallocated eventually. So, in this case, we can deallocate arrayDynamic like this:
delete [] arrayDynamic;
A two-dimensional dynamic array is defined analogously:
foo** arrayDynamic2D;
arrayDynamic2D = new foo*[bar];
for (int i = 0; i < bar; i++)
arrayDynamic2D[i] = new foo[baz];
and deallocated in a similar fashion:
for (int i = 0; i < bar; i++)
delete [] arrayDynamic2D[i];
delete [] arrayDynamic2D;
Static memory is allocated in the stack whereas dynamic memory is allocated in the heap.
It's not possible to do it in C++ using static arrays. Use std::vector in a hierarchical way (i.e. vectors of vectors) to implement a multi-dimensional array easily (though not necessarily very efficiently).
E.g.
std::vector<std::vector<double> > array(nrows, std::vector<double>(ncols));
creates a nrows x ncols matrix.
You need dynamic memory allocation using new:
int **User_Groups = new int*[definedgroups];
//Allocate memory for 2nd dimension
for (int i = 0; i < 4; ++i)
User_Groups[i] = new int[4];

allocation of a pointers to fixed size arrays

I have 2 doubts regarding basics of pointers usage.
With the following code
int (*p_b)[10];
p_b = new int[3][10];
// ..do my stuff
delete [] p_b
p_b is pointing to an array of 3 elements, each having fixed-size length of 10 int.
Q1:
How to declare p_b if I want that each element be a pointer to a fixed array size?
Basically I want the following
p_b[0] = pointer to a fixed-array size of 10
p_b[1] = pointer to a fixed-array size of 10
// ... and so on
I was thinking to int (** p_b)[10] but then I don't know how to use new to allocate it? I would like to avoid falling back to more general int** p_b
Q2:
Is per my original code sample above, how to call new so that p_b points to a unique fixed-size array of 10 int other than calling p_b = new int[1][10] ? To free memory I have to call delete[] while I cannot find an expression where I can call only simply delete.
p_b is pointing to an array of 3 elements, each having fixed-size length of 10 int.
How to declare p_b if I want that each element be a pointer to a fixed array size?
Does your first sentence not completely cover that question?
Is per my original code sample above, how to call new so that p_b points to a unique fixed-size array of 10 int other than calling p_b = new int[1][10]? To free memory I have to call delete[] while I cannot find an expression where I can call only simply delete.
I completely do not understand why this is a problem, but you could do it by wrapping your array inside another type... say std::array, boost::array or std::vector.
First of all, if your new expression has square brackets (new somtype[somesize]), your delete has to have square brackets as well (delete [] your_pointer).
Second, right now you've defined p_b to be a single pointer to some data. If what you really want is an array of pointers, then you need to define it as an array. Since you apparently want three independent arrays, you'll have to allocate each of them separately. It's probably easiest if you start with a typedef:
typedef int *p_int;
p_int p_b[3];
Then you'll allocate your three arrays:
for (int i=0; i<3; i++)
p_b[i] = new int[10];
To delete those, you'll need to delete each one separately:
for (int i=0; i<3; i++)
delete [] p_b[i];
I definitely agree with #Tomalak that you should almost never mess with things like this yourself though. It's not clear what you really want to accomplish, but it's still pretty easy to guess that chances are quite good that a standard container is likely to be a simpler, cleaner way to do it anyway.
Here's an example of how to implement Q1:
int main()
{
typedef int foo[10];
foo* f = new foo[3];
f[0][5] = 5;
f[2][7] = 10;
delete [] f;
}
As for Q2, the only way to delete memory allocated with new[] is with delete[]. If you personally don't want to write delete [], you can use a vector or another STL container. Really, unless this is some hardcore uber-optimisation, you should be using vectors anyway. Never manage memory manually unless you are absolutely forced to.
To use a raw pointer to manage a 2-d array you must first create a pointer to a pointer to array element type that will point to each row of the array. Next, each row pointer must be assigned to the actual array elements for that row.
int main()
{
int **p;
// declare an array of 3 pointers
p = new int*[3];
// declare an array of 10 ints pointed to by each pointer
for( int i = 0; i < 3; ++i ) {
p[i] = new int[10];
}
// use array as p[i][j]
// delete each array of ints
for( int i = 0; i < 3; ++i ) {
delete[] p[i];
}
// delete array of pointers
delete[] p;
}
A far easier solution is to use std::array. If your compiler does not provide that class you can use std::vector also.
std::array<std::array<int,10>,3> myArr;
myArr[0][0] = 1;
For Q1, I think you want
int (*p[3])[10];
Try cdecl when you're unsure.
Your other question seems to be well answered by other answers.
regards,
Yati Sagade
Actually, nobody posted an answer to your exact question, yet.
Instead of
int (*p_arr)[10] = new int[3][10];
// use, then don't forget to delete[]
delete[] p_arr;
I suggest using
std::vector<std::array<int, 10>> vec_of_arr(3);
or if you don't need to move it around and don't need runtime length:
std::array<std::array<int, 10>, 3> arr_of_arr;
Q1
How to declare p_b if I want that each element be a pointer to a fixed array size?
int(**pp_arr)[10] = new std::add_pointer_t<int[10]>[3];
for (int i = 0; i < 3; ++i)
pp_arr[i] = new int[1][10];
// use, then don't forget to delete[]
for (int i = 0; i < 3; ++i)
delete[] pp_arr[i];
delete[] pp_arr;
The modern variant of that code is
std::vector<std::unique_ptr<std::array<int, 10>>> vec_of_p_arr(3);
for (auto& p_arr : vec_of_p_arr)
p_arr = std::make_unique<std::array<int, 10>>();
or if you don't need to move it around and don't need runtime length:
std::array<std::unique_ptr<std::array<int, 10>>, 3> arr_of_p_arr;
for (auto& p_arr : arr_of_p_arr)
p_arr = std::make_unique<std::array<int, 10>>();
Q2
Is per my original code sample above, how to call new so that p_b points to a unique fixed-size array of 10 int other than calling p_b = new int[1][10]?
Not without wrapping the array into another type.
std::array<int, 10>* p_arr = new std::array<int, 10>;
// use, then don't forget to delete
delete p_arr;
You can replace std::array<int, 10> with your favourite array-wrapping type, but you cannot replace it with a fixed-size array alias. The modern variant of that code is:
auto p_arr = std::make_unique<std::array<int, 10>>();

Multi-dimensional array and pointers in C++?

int *x = new int[5]();
With the above mentality, how should the code be written for a 2-dimensional array - int[][]?
int **x = new int[5][5] () //cannot convert from 'int (*)[5]' to 'int **'
In the first statement I can use:
x[0]= 1;
But the second is more complex and I could not figure it out.
Should I use something like:
x[0][1] = 1;
Or, calculate the real position then get the value
for the fourth row and column 1
x[4*5+1] = 1;
I prefer doing it this way:
int *i = new int[5*5];
and then I just index the array by 5 * row + col.
You can do the initializations separately:
int **x = new int*[5];
for(unsigned int i = 0; i < 5; i++)
x[i] = new int[5];
There is no new[][] operator in C++. You will first have to allocate an array of pointers to int:
int **x = new int*[5];
Then iterate over that array. For each element, allocate an array of ints:
for (std::size_t i = 0; i < 5; ++i)
x[i] = new int[5];
Of course, this means you will have to do the inverse when deallocating: delete[] each element, then delete[] the larger array as a whole.
This is how you do it:
int (*x)[5] = new int[7][5] ;
I made the two dimensions different so that you can see which one you have to use on the lhs.
Ff the array has predefined size you can write simply:
int x[5][5];
It compiles
If not why not to use a vector?
There are several ways to accomplish this:
Using gcc's support for flat multidimensional arrays (TonyK's answer, the most relevant to the question IMO). Note that you must preserve the bounds in the array's type everywhere you use it (e.g. all the array sizes, except possibly the first one), and that includes functions that you call, because the produced code will assume a single array. The allocation of $ new int [7][5] $ causes a single array to be allocated in memory. indexed by the compiler (you can easily write a little program and print the addresses of the slots to convince yourself).
Using arrays of pointers to arrays. The problem with that approach is having to allocate all the inner arrays manually (in loops).
Some people will suggest using std::vector's of std::vectors, but this is inefficient, due to the memory allocation and copying that has to occur when the vectors resize.
Boost has a more efficient version of vectors of vectors in its multi_array lib.
In any case, this question is better answered here:
How do I use arrays in C++?