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

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];

Related

What are the different ways of declaring a 2D array in 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|
| | | ^ ^ ^
| | -------- | |
| ---------------------------- |
------------------------------------------------

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 ...

C++ Syntax - Multidimensional Dynamic Array

I need help understanding the syntax of multidimensional arrays in C++. In the book I'm learning C++ from, the code snippet looks like this:
typedef int* IntArrayPtr;
IntArrayPtr *m = new IntArrayPtr[num_rows];
for(int i = 0; i < rows; i++){
m[i] = new int[num_columns]
}
My question is this: Why is there a star infront of the m? To me when I see
new IntArrayPtr[num_rows];
that's enough information to tell the compiler that it's an array of pointers that point to int. The star just makes it confusing. Is there something I'm missing here?
Keep in mind that what you have when you do new IntArrayPtr[num_rows] is an array of IntArrayPtrs. In C new[], "allocates size bytes of storage, suitably aligned to represent any object of that size, and returns a non-null pointer to the first byte of this block." So new[] is returning you a pointer to the first element of your array.
For example if num_rows is 3 this is what gets allocated in memory:
m --> [IntArrayPtr]
[IntArrayPtr]
[IntArrayPtr]
m being a pointer is what allows you to use the index operator on it: m[1] returns you the second IntArrayPtr in m.
m is the pointer to pointer which handles starting points of columns as a row. Example of this example in c
int **arr=(int**)malloc(num_rows * (sizeof(int*) ) );
for(i=0;i<row;i++)
{
arr[i]=(int*)malloc(sizeof(int)*col_rows);
}
if we use typedef,
typedef int* IntArrayPtr;
IntArrayPtr *arr=(IntArrayPtr*)malloc(num_rows * (sizeof(IntArrayPtr) ) );
for(i=0;i<row;i++)
{
arr[i]=(IntArrayPtr)malloc(sizeof(int)*col_rows);
}
As you see, firstly we create a pointer array to hold pointers of columns. After that we allocate a place for every columns of array and assign starting points of one dimensional column arrays to one dimensional pointer array.

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.

2D-array as argument to function

Why can't you declare a 2D array argument in a function as you do with a normal array?
void F(int bar[]){} //Ok
void Fo(int bar[][]) //Not ok
void Foo(int bar[][SIZE]) //Ok
Why is it needed to declare the size for the column?
Static Arrays:
You seem not to have got the point completely. I thought to try to explain it somewhat. As some of the above answers describe, a 2D Array in C++ is stored in memory as a 1D Array.
int arr[3][4] ; //consider numbers starting from zero are stored in it
Looks somewhat like this in Memory.
1000 //ignore this for some moments 1011
^ ^
^ ^
0 1 2 3 4 5 6 7 8 9 10 11
|------------| |-----------| |-------------|
First Array Second Array Third Array
|----------------------------------------------|
Larger 2D Array
Consider that here, the Bigger 2D Array is stored as contiguous memory units. It consists of total 12 elements, from 0 to 11. Rows are 3 and columns are 4. If you want to access the third array, you need to skip the whole first and second arrays. That is, you need to skip elements equal to the number of your cols multiplied by how many arrays you want skip. It comes out to be cols * 2.
Now when you specify the dimensions to access any single index of the array, you need to tell the compiler beforehand exactly how much elements to skip. So you give it the exact number of cols to perform the rest of the calculation.
So how does it perform the calculation? Let us say it works on the column major order, that is, it needs to know the number of columns to skip. When you specify one element of this array as...
arr[i][j] ;
Compiler performs this calculation automatically.
Base Address + (i * cols + j) ;
Let us try the formula for one index to test its veracity. We want to access the 3rd element of the 2nd Array. We would do it like this...
arr[1][2] ; //access third element of second array
We put it in the formula...
1000 + ( 1 * 4 + 2 )
= 1000 + ( 6 )
= 1006 //destination address
And we reach at the address 1006 where 6 is located.
In a nutshell, we need to tell the compiler the number of cols for this calculation. So we send it as a parameter in a function.
If we are working on a 3D Array, like this...
int arr[ROWS][COLS][HEIGHT] ;
We would have to send it the last two dimensions of the array in a function.
void myFunction (int arr[][COLS][HEIGHT]) ;
The formula now would become this..
Base Address + ( (i * cols * height) + (j * height) + k ) ;
To access it like this...
arr[i][j][k] ;
COLS tell the compiler to skip the number of 2D Array, and HEIGHT tells it to skip the number of 1D Arrays.
And so on and so forth for any dimension.
Dynamic Arrays:
As you ask about different behavior in case of dynamic arrays which are declared thus..
int ** arr ;
Compiler treats them differently, because each index of a Dynamic 2D Array consists of an address to another 1D Array. They may or may not be present on contiguous locations on heap. Their elements are accessed by their respective pointers. The dynamic counterpart of our static array above would look somewhat like this.
1000 //2D Pointer
^
^
2000 2001 2002
^ ^ ^
^ ^ ^
0 4 8
1 5 9
2 6 10
3 7 11
1st ptr 2nd ptr 3rd ptr
Suppose this is the situation. Here the 2D Pointer or Array on the location 1000. It hold the address to 2000 which itself holds address of a memory location. Here pointer arithmetic is done by the compiler by virtue of which it judges the correct location of an element.
To allocate memory to 2D Pointer, we do it..
arr = new int *[3] ;
And to allocate memory to each of its index pointer, this way..
for (auto i = 0 ; i < 3 ; ++i)
arr[i] = new int [4] ;
At the end, each ptr of the 2D Array is itself an array. To access an element you do...
arr[i][j] ;
Compiler does this...
*( *(arr + i) + j ) ;
|---------|
1st step
|------------------|
2nd step
In the first step, the 2D Array gets dereferenced to its appropriate 1D Array and in the second step, the 1D Array gets dereferenced to reach at the appropriate index.
That is the reason why Dynamic 2D Arrays are sent to the function without any mention of their row or column.
Note:
Many details have been ignored and many things supposed in the description, especially the memory mapping just to give you an idea.
You can't write void Foo(int bar[][]), because bar decays to a pointer. Imagine following code:
void Foo(int bar[][]) // pseudocode
{
bar++; // compiler can't know by how much increase the pointer
// as it doesn't know size of *bar
}
So, compiler must know size of *bar, therefore size of rightmost array must be provided.
Because when you pass an array, it decays to a pointer, so excluding the outer-most dimension is ok and that's the only dimension you can exclude.
void Foo(int bar[][SIZE])
is equivalent to:
void Foo(int (*bar)[SIZE])
The compiler needs to know how long the second dimension is to calculate the offsets. A 2D array is in fact stored as a 1D array.
If you want to send an array with no known dimensions, consider using pointer to pointers and some sort of way to know the dimension yourself.
This is different from e.g. java, because in java the datatype also contains the dimension.
Since static 2D arrays are like 1D arrays with some sugar to better access data, you have to think about the arithmetic of pointers.
When the compiler tries to access element array[x][y], it has to calculate the address memory of the element, that is array+x*NUM_COLS+y. So it needs to know the length of a row (how many elements it contains).
If you need more information I suggest this link.
there are basically three ways to allocate a 2d array in C/C++
allocate on heap as a 2d array
you can allocate a 2d array on the heap using malloc such as:
const int row = 5;
const int col = 10;
int **bar = (int**)malloc(row * sizeof(int*));
for (size_t i = 0; i < row; ++i)
{
bar[i] = (int*)malloc(col * sizeof(int));
}
this is actually stored as an array of arrays therefore isn't necessarily
contiguous in memory. note that this also means there will be a pointer for
each array costing yout extra memory usage (5 pointers in this example, 10
pointers if you allocate it the other way around). you can pass this array to
a function with the signature:
void foo(int **baz)
allocate on heap as 1d array
for various reasons (cache optimizations, memory usage etc.) it may be
desirable to store the 2d array as a 1d array:
const int row = 5;
const int col = 10;
int *bar = (int*)malloc(row * col * sizeof(int));
knowing second dimension you can access the elements using:
bar[1 + 2 * col] // corresponds semantically to bar[2][1]
some people use preprocessor magic (or method overloading of () in C++) to
handle this automatically such as:
#define BAR(i,j) bar[(j) + (i) * col]
..
BAR(2,1) // is actually bar[1 + 2 * col]
you need to have the function signature:
void foo(int *baz)
in order to pass this array to a function.
allocate on stack
you can allocate a 2d array on stack using something like:
int bar[5][10];
this is allocated as a 1d array on the stack therefore compiler needs to know
the second dimension to reach the element you need just like we did in the
second example, therefore the following is also true:
bar[2][1] == (*bar)[1 + 2 * 10]
function signature for this array should be:
void foo(int baz[][10])
you need to provide the second dimension so that compiler would know where to reach in memory. you don't have to give the first dimension since C/C++ is not a safe language in this respect.
let me know if I mixed up rows and columns somewhere..