A pointer has two parts:
1. It is a pointer.
2. The type it points to.
Lets look at your
int *p = new int[10];
1. The p is a pointer.
2.The pointed to type is
int
What about the right side?
The new returns an address of type int object. A pointer stores an address, so the p gets what it wants.
The new[] allocates memory not for just one int, but for many. The p, however, does not know whether it has an address of statically or dynamically allocated memory (or invalid address) nor whether consecutive memory location contain objects of same type. The type information within p does affect how many bytes is added to the address, when you write
p+7
.
Lets rewrite a more generic example:
T * p = new T [n];
You had T=int, n=10. Change the T into
int *
.
Now we have:
int * * p = new int * [n];
The p is a pointer to a
pointer to int, but since we did allocate an array, the p is effectively a pointer to an
array of pointers.
The
*p
(aka
*(p+0)
) is now a pointer to int. Lets allocate an array of int and store its address in *p
1 2 3 4 5
|
int* *p = new int* [rows];
*p = new int [rows*cols];
delete [] *p;
delete [] p;
|
Only two issues remain:
1. The *(p+0) does give a pointer to the first element of the array, but the *(p+k) have to be initialized to have pointers to the beginning elements of the other rows. That I leave to you. Simple pointer math.
2. All exit routes must do the deallocation properly. That is not trivial and is the main reason why code should avoid plain new&delete. One can use smart pointers, STL containers, or custom "2D array" types that encapsulate the memory management. You, however, probably have to play with raw pointers
for educational purposes.