To declare an array of pointer to int
, you don't need parentheses:
int* p[10];
will do. To declare a pointer to an array of 10 integers, you do need parentheses:
int (*p)[10];
This is simply a question of operator precedence. []
binds more strongly than *
in a declarator. Thus, without parentheses, int *p[10];
is going to be an array of ten ([10]
applies first) pointers to (*
applies second) int
. The parentheses in int *(p[10]);
are superfluous. int (*p)[10];
on the other hand, declares a pointer to (*
applies first due to the ()
) an array of 10 ([10]
applies second) int
.
A new
expression is no different. The only difference is that your declarator contains no identifier because you're not declaring a variable that is to be given a name, you're just spelling out a type. new
figures out how much storage it needs based on the type of the object you asked it to create.
To simply declare the type "array of ten pointers to int
", you'd write int* [10]
. And to declare the type "pointer to array of ten int", you'd write int (*)[10]
.
There is one problem in the context of new
, however. That problem is that the bounds of an array type in C++ have to be constant expressions (i.e., compiletime constants). Arrays of dynamic size do not exist in the C++ type system. However, the whole point of new
is to create objects dynamically, arrays of dynamic size in particular.
To get around this problem, new
must avoid to ever require naming an array of dynamic size as a type. The way this is currently achieved in the C++ specification is by having a completely separate declarator grammar for new-expressions [expr.new]/1. What happens there is that top-level array bounds are peeled off and treated separately. When you write new int[n]
, you create an array of n
objects of type int
, where n
does not have to be a constant-expression. Contrary to the way new
operates on other types, if you ask new
to create an object of array type, new
does not return a pointer to the array of the given type, but a pointer to the first element of the array it created instead. Thus, even if you create an array of a size that is not a constant-expression, the type of the result of the new-expression is never going to be "array of dynamic size", but always something that actually exists in the type system…
There is one escape hatch thought. The grammar for a new-expression is [expr.new]/1
new-expression:
::
opt new
new-placementopt new-type-id new-initializeropt
::
opt new
new-placementopt (
type-id )
new-initializeropt
As you can see, a new-expression can be given either a new-type-id (which is the separate grammar that allows for creating arrays of dynamic size) or a normal type-id in parentheses.
Thus, it is actually possible to create a single pointer to an array of ten int
via new
:
int (**p)[10] = new (int(*)[10]);