The declarations are completely different.
The first case,
int x[10];
declares x
as an array of 10
integer, whereas the second case,
int* x = new int[10];
declares x
as a pointer to int
- a variable with value equal to an address of an int
, and initialises that pointer to the result of a new expression (new int [10]
) that dynamically allocates an array of ten integers.
Not withstanding the differences, the two can be used in similar ways;
- array syntax (e.g.
x[i]
, where i
is an integral value between 0
and 9
inclusive) can be used to set or retrieve values of the respective arrays in the above syntax;
- pointer arithmetic can be used to obtain an address of an element of the array (e.g.
x + i
is equivalent to &x[i]
for i
between 0
and 10
inclusive. [yes, it is possible to obtain "one past the end" address];
- Pointer dereferencing and array access are equivalent. i.e.
*(x+i)
and x[i]
are equivalent, for i
between 0
and 9
[dereferencing a "one past the end" pointer gives undefined behaviour].
However, there are also some key differences, for example;
Results of the sizeof
operator. sizeof(x)
gives different values in the two cases.
- In the first case
sizeof(x) == sizeof(int)*10
. sizeof(int)
gives an implementation-defined balue, but sizeof(x)/sizeof(*x)
will always give the number of elements in the array (i.e. a std::size_t
with value 10
).
- In the second,
sizeof(x) == sizeof(int *)
- which is an implementation-defined value. The value of sizeof(x)/sizeof(*x)
is practically exceedingly unlikely to yield a value of 10
. Which means this technique cannot be used to obtain the number of elements.
Lifetime.
In the first case, the lifetime of x
depends on the scope in which the declaration occurs. If the declaration occurs at file scope (i.e. in a compilation unit, outside any function block), then x
has static storage duration (so exists for as long as the program is running). If the declaration occurs in a block, x
- and all its elements - ceases to exist when the block ends. For example
{
int x[10];
} // x and all its elements cease to exist here
In the second case, it is only the pointer x
that has a lifetime that depends on scope. The dynamically allocated memory (the result of new x[10]
) is never deallocated. This means the lifetime of x
and lifetime of the (dynamically allocated) array it references are decoupled, which brings us to a third difference .....
Result of assignment An array cannot be reassigned, a pointer can (unless appropriately const
qualified).
Consider a context of
// x as previously defined in one or the other form
int y[10];
int z;
x = y;
x = &z;
In the first case, both assignments will result in a compiler diagnostic - the assignments are invalid. In the second case, the assignments are valid and cause x
to point at the address of (the first element of) y
and to the address of z
respectively. Unless the value of x
is stored in another pointer before reassignment, the memory allocated by the new expression (new int [10]
) is leaked - it is no longer accessible by the program, but is not released either.