10

Using Visual Studio Express 2013. I thought I understood static vs dynamic arrays, but the following has me confused:

int* a = new int[3]; \\ dynamic array
int** pa = &a;

int b[3]; \\ static array
int** pb = &b; \\ error: cannot convert from 'int (*)[3]' to 'int **'

Ok, so I try int (*)[3] pb = &b; but it's not even syntactically correct. The Locals Window says pb is an int[3], but int[3]* pb = &b; is also incorrect.

enter image description here

It also seems strange to me that b has the same value as pa. If I replace the declaration int b[3]; with a declaration + initialization int b[3] = {}; then that oddity disappears, so maybe it's just a VS bug:

enter image description here

But I still can't get at the address of the static array. If I type &b in the Immediate Window then I get exactly the same output as if I just typed b, which again seems strange by comparison with '&a' and 'a' which are clearly different things:

enter image description here

George Skelton
  • 1,095
  • 1
  • 10
  • 22
  • 2
    It's worth pointing out that the declaration of `pb` should look like `int (*pb)[3] = &b;`. You just had the identifier in the wrong place. – Joseph Mansfield Jun 30 '14 at 21:42

2 Answers2

7

A dynamic array is a very weird part of C++. It's a type that is never the type of any expression in the language, and you can never see a dynamic array as a whole. When you say new T[N], all you get is a pointer to the first element of the fictitious array of type T[N]. (Note also that this is a truly "dynamic type"!)

By contrast, your b is an actual array object, so naturally its address has type "pointer to array". If you wanted a pointer to a pointer its first element, you'd first have to create such a pointer:

int b[3];
int * b0 = &b[0];  // or just "int * b0 = b;" :-S
int ** pb = &b0;

Tbe variable b0 here is the analogue of your variable a in the dynamic example - a pointer variable containing the address of the first array element.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
5

@Kerrek said that dynamic arrays are weird part of C++; I say static arrays are weird, with their semantics unlike anything else in the language.

Given an array:

int foo[3] = { 1, 2, 3 };

Pointer to an array:

int (*pfoo)[3] = &foo;

Reference to an array (surprisingly powerful with templates):

int (&rfoo)[3] = foo;

Pointer to the first element:

int *pa = &foo[0];
assert(*pa == 1);
int *pb = foo; // auto decay!
assert(pa == pb);
assert(pa == foo); // auto decay strikes again
assert(pa+0 == foo+0); // and again

Note that the decay-to pointer and pointer to the actual array have same value, since they point to the same memory location:

assert((void*)foo == (void*)&foo);

But for any array size greater than 1 this assertion will fail:

assert((void*)(foo+1) == (void*)(&foo+1));

Because:

static_assert(sizeof(*(foo+0)) == sizeof(int), "");
static_assert(sizeof(*(&foo)) == sizeof(int[3]), "");

Copy-assignment is not possible:

int bar[3] = foo; // compile error!

... unless it happens in the compiler-generated code:

struct workaround { int foo[3]; };
workaround a = { { 1, 2, 3 } };
workaround b = a;
assert(b.foo[0] == 1); // the array got copied!

Can't be a result of a function:

int (func1())[3]; // syntatically correct, but prohibited by C++

So one must resort to workarounds:

std::array<int, 3> func2();
void func3( int (&out_arr)[3] );

If that's not weird, then I don't know what is.

(Despite that, stack allocation FTW).

gwiazdorrr
  • 6,181
  • 2
  • 27
  • 36