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.