Let see, If I can help ....
Understanding 1-D, 2-D, 3-D
and in turn N-D dynamic arrays and
corresponding pointer declaration: all pointer variable are in stack and arrays
will be in heap[by - Himadri Sekhar Das/APT]
I've a quick pictorial reference as follows for the 3D dynamic array
realization ...through pointer...using new operator/keyword... look into it will help us
any more .... This is one application/uses of pointer.
1. Our target is to create a 3-D dynamic
array at runtime
2. for this we've to allocate a storage/memory by new keyword [in c++] following by
the type of object. i.e. in our case
the object is a 3D array. [or malloc()/calloc() in C ]
3. But how can we represent the 3D array with new is to be realized/visualize
first. If we do that then the pointer declaration for the same and
corresponding dereferencing will be very easy to remember.
4. Let me introduce how we've to proceed for the same. If we follow it then 4D
or ND dynamic array will be a game of one hand. So let's proceed.
5. Since we will want to allocate memory at runtime, we've to use the new
keyword of C++ which will return a pointer to that allocated block of memory.
So we've to declare a pointer variable that can capable of holding the address
of corresponding block of memory. So the pointer declaration and understanding
is a vital.
Visual
representation of 1-D, 2-D, 3-D and 4-D and N-D arrays and corresponding
pointer declaration: all pointer variable are in stack and arrays will be in
heap
![]()
D:\Himadri\3D_DArray1.JPG

All arrays are dynamically allocated at heap using new
operator/keyword but the pointer p2 is in caller function stackframe. [Ref: be googled by ‘Run Time Heap and Stack'
and go through http://www.cs.jcu.edu.au/Subjects/cp2003/1997/foils/heapAndStack/heapAndStack.html
]
D:\Himadri\3D_DArray2.JPG
![]()
Lets, do some rehearse before we proceed further. Hope
everybody knows what's a ‘type'
represent in connection with computer language.
A.
a pointer declaration that can point to an int
type of storage
int *p;
i) if we've a int
type of storage namely x, [ i.e. int x; ]
then we can store the address of the storage x into the pointer p. [ p = &x; ]
ii) if we've a int
type of array-storage namely x, [
i.e. int
x[10]; ] then we can store the address of the individual storage of each
element of the array x into the
pointer p [ p = &x[0] or ... or p =
&x[9] ] , because each element of the array x is a storage of type int. and we can use the rule A-i). NB. no array
element has an individual identity but the array has and we can use the identity
[ i.e. array-name ] to represent each of its element as above.
or
the address of the first element of array x
into the pointer p [ p = x; ], because we know that any
array name is a pointer and points to its first element. So for representing
the first element's address we can use only array-name x instead of &x[0]
symbol.
iii) so if we initialize such
a pointer with the array-name of 1D array [ p = x; ] then we can represent each elements of it by notation *p, *(p + 1), ...,*(p + 9) since the
pointer increment by one points to the next storage of same type [ our case int, ie
16/32 bits ]. We can use this simple but
restricted pointer increment or decrement math to access any no of storage of
same type that gives us an illusion of an array.
So the conclusion is if we can initialize a pointer with an array-name then
it is possible to access the whole array by that pointer. So here we can
conclude that a simple pointer [ int *p ] can point to a single element of corresponding
type or can point to an 1-D array of corresponding type. We can also declare the
pointer variable p as int
(*p)[10]; but this statement required constant expression 10 at compile
time resolution, which we want to avoid as we want dynamic size of 1-D array
not fixed at compile time e.g. 10.
Ps. p = new
int [5]; statement represents dynamic 1-D
array storage/memory allocation and initializing p with the start address of the storage. Since new will invoke at
run time the size 5 has no must rule to be required at compile
time, like constant expression. We can get the size from a variable at run time
but it should be valid before the invocation of new.
So we can write above statement as p = new int [variable1]; please check it out.
B.
now lets proceed to a pointer declaration that can point to a 2-D array of type
int
i) from the
conclusion of section A we now easily say that if *p can able to represent the
1-D array then the **p1 will be able to represent the 2-D array. But this is
not sufficient to realize/visualize the 2-D array. Lets proceed whether **p1
really capable to represent the 2-D array at all. Then we can reach the
conclusion by ourselves.
ii) what is a 2-D array? By
our every day life we can take several examples. The score board of a
Cricket-Match, The chart of airplane schedule, The time table of train, the
computer spreadsheet table, or a table in a database etc. all of these are
example of 2-D array. Each of these has 2-Dimension like rows and columns.
iii) we can break the point
ii) as follows : A 2-D array is nothing but a collection-of-rows [ each row is
an 1-D array] or collection-of-columns [ each column is an 1-D array]. Now
think how we can keep all these rows of 1-D array together, so that we and
access each row [ 1-D array] ? Think and think, the gray cell of your brain is
flushing now, yes you are right it can be possible if we can keep all rows [ i.e.
1-D array ] name together - in another array [ say y[] ]. Since any 1-D array name is a pointer to itself so we've to keep
in mind that the array y should be declared
in such a way so that it can be capable of holding of another 1-D array name -
i.e. a pointer.
so, how the declaration of the array y
should be - is as follows : please confirm it
int* y[5];
at this point lets verify
our logic once more.
int x[10]; statement denotes an 1-D
array of 10 int
type elements.
so, int* y[5]; statement will denotes
an 1-D array of 5 int*
type elements.
now think what's int* represent is nothing but
a pointer to int
type storage, but we have a previous logic that using int*
[ i.e. type of variable p ] make a
variable i.e. p to represent an 1-D array. So,
we can say that int*
y[5] will represent and array whose each element can be capable of
representing 1-D array, or collectively the array y can be capable of representing 5 no. of 1-D array, or y is an 1-D array whose each element is
a pointer to another 1-D array.
iv) the declaration procedure int* y[5]
is required constant expression 5. So this declaration is not use full if we
want to crate a collection of 1-D arrays and want to store each 1-D arrays to
another 1-D array at run time. So indeed we need a pointer declaration that can
capable of representing int* y[5]. And we can do it by the declaration int* (something that will represent y)[5] => int* (*p1)[5];
as because we've previous logic that *p1
declaration is capable of representing y; => int** p1;
v) we can keep above pointer
declaration as follows: int* (*p1)[5]; but again it will require constant
expression 5, at compile time resolution, the same reason for which we've to
discard the previous pointer declaration, but we can use int** p1; removing bracket and
array symbol. This is logical because think the type of each element of int* y[5];
is a pointer to an int [not integer]. But the name y is also a pointer, which is pointing
to each of its element. So it seems that each element of y is of type pointer to pointer to an int.
Conclusion: Logic is simple pointer math gives us an illusion of array,
and a pointer variable does not need to be initialize at compile time if we
declare it in proper way.
So, int
** p1 can represent a 2-D dynamic array.
C. Similarly the pointer declaration of 3-D dynamic array.
i) from the
conclusion of section A and B we now easily say that if *p can able to
represent the 1-D array and the **p1 can be able to represent the 2-D array
then the ***p2 will be able to represent the 3-D array. But this is not
sufficient to realize/visualize the 3-D array. Lets proceed whether ***p2
really capable to represent the 3-D array at all. Then we can reach the
conclusion by ourselves.
ii) what is a 3-D array? By
our every day life we can take several examples. The The hourly collection of chart
of airplane schedule for a day, The hourly collection of time table of train,
the collection computer spreadsheet table/sheet, or a collection of similar
type table in a database, or collection of all points of Z-axis that points to
individual XY plane in Cartesian co-ordinate system etc. all of these are example
of 3-D array. Each of these has 3-Dimension like rows, columns and heights or
x-axis, y-axis and z-axis.
iii) we can break the above point as follows: A 3-D array
is nothing but a collection [ say heights, which is an 1-D array whose each
element is capable of holding another 2-D arrays ] of 2-D arrays which in turn
consists of collection-of-rows [ each row is an 1-D array] or collection-of-columns
[ each column is an 1-D array]. Now think how we can keep all these rows of 2-D
array together, so that we can access each plane/table [ 2-D array] ? Think and
think, the gray cell of your brain is flushing now, yes you are right it can be
possible if we can keep all plane/table [ i.e. 2-D array ] name together - in
another array [ say z[] ]. Since any
2-D array name is also a pointer to itself so we've to keep in mind that the
array z should be declare in such a
way so that it can be capable of holding of another 2-D array name -
i.e. each element of z[] be a
pointer to a pointer to an int or int array.
so how the declaration of the array z
should be - is as follows : please confirm it
int** z[3];
at this point lets verify
our logic once more.
int x[10]; statement denotes an 1-D
array of 10 int
type elements.
so, int* y[5]; statement denotes an 1-D
array of 5 int*
type elements or 5 no. of 1-D array or a 2-D array.
so, int** z[3];
statement will denote an 1-D array of 3 int** type
elements or 3 no. of 2-D array [ as **p1 represents 2-D array ] or 3-D array.
now think what's int* represent is nothing but
a pointer to int
type storage, but we have a previous logic that using int*
[ i.e. type of variable p ] make a
variable i.e. p to represent an 1-D array. So,
we can say that int*
y[5] will represent and array whose each element can be capable of representing
1-D array, or collectively the array y
can be capable of representing 5 no. of 1-D array, or y is an 1-D array whose each element is a pointer to another 1-D
array. And int**
z[3] will represent an 1-D array whose each element is of type int** i.e. pointer to pointer to int or pointer to a 2-D array.
iv) the
declaration procedure int** z[3] is required constant expression 3. So
this declaration is not use full if we want to crate a collection of 2-D arrays
and want to store each 2-D arrays to another 1-D array at run time. So indeed
we need again a pointer declaration that can capable of representing int** z[3].
And we can do it by the declaration int** (something
that will represent z)[3] => int**
(*p2)[3]; as because we've previous
logic that **p2 declaration is
capable of representing z; => int*** p2;
v) we can
keep above pointer declaration as follows: int** (*p2)[3]; but again it will require
constant expression 3, at compile time resolution, the same reason for which
we've to discard the previous pointer declaration, but we can use int*** p2;
removing bracket and array symbol. This is logical because think the type of
each element of int**
z[3]; is a pointer to a pointer an int [not integer]. But the name z is also a pointer, which is pointing
to each of its element. So it seems that each element of z is of type pointer to pointer to pointer an int.
Conclusion: Logic is simple pointer math gives us an illusion of array,
and a pointer variable does not need to be initialize at compile time if we
declare it in proper way.
So, int***
p2; can represent a 3-D dynamic array.
My Suggestion:
Don't go through my logic explanation but the implementation details i.e. the
realization and visualization of a 3-D array with new
keyword as follows and the build up your logic of understanding to make
understand yourself.
Think a bit more:
what is the difference
between int* p1; and int (*p2)[10]; ?
Let consider we've an 1-D int
array as follows: int a[10];
then, [try it out]
1. p1 =
a; or p2 = &a; [p1 points to elements of a, but p2 points to the array a,
needs the reference of a (i.e. &a) to initialize.]
2. p1 + 1 points to a[1] but (p2 + 1) points to what?
3. so by p1, p1 + 1, ... and so on we can traverse through the array a, but with
p2, p2 + 1, ... what?
4. in case of 2-D or more-D array, declaration of p1(**p1, ***p1 etc.) doesn't
required any constant expression at
compile time but declaration of p2(
(*p2)[][10], (*p2)[][3][4] etc. ). Coz, Compiler behaves like this way.
CODE Example in c++:
#include <iostream>
using namespace
std;
int main()
{
int x, y, z; cout <<
"Enter array dimensions: "; cin >> x >> y >> z;
int*** p2 = new
int** [x]; /* The pointer p2 resides at main()
function's stack-frame, but storage at heap*/
for
(int i = 0; i < x; i++) { /* Dynamic allocation of 1-D array that
will points to a 2-D array in heap*/
p2[i]= new int*
;
}
for
(int i = 0; i < x; i++) { /* Dynamic allocation of 2-D array in
heap*/
for (int j = 0; j < y; j++) {
p2[i][j]=
new int
;
}
}
................................. /* initializing each element of
3-D array, accessing and other logic */
}
PS: We should declare int*** p2, because the memory for 3-D array will be allocated dynamically
according to input x, y, z at runtime. A typical use of pointer. And after all
please feel free to rectify this doc in any context if required. So,
N-dimensional dynamic array using pointer is no more an issue. Moreover, if we
use any generic type instead of new int we will get the corresponding
template.J
Could not able to insert images, any help for the same? 'll try
Thanks and Regards
Himadri Sekhar Das
APT/India