7

When I declare a new array like this:

int foo[5]

Is foo really a pointer to the first element of the array? Would I be able to do this:

*(foo+2)

to access the third element of the array? Let's say I'm making a 2D array:

int foo[3][4]

Is foo now a int**?

9
  • 11
    Is foo really a point to the first element of the array? - No, it's an array. Is foo now a int**? - No, it's a 2D array. See arrays Commented Dec 5, 2014 at 13:27
  • @chris, so if I wanted to iterate over it using pointer notation, I'd need to make a int* ptr = &foo[0]? Commented Dec 5, 2014 at 13:29
  • @maxmackie int* ptr = foo would be enough. Commented Dec 5, 2014 at 13:29
  • 3
    Have a look here: stackoverflow.com/questions/4810664/… Commented Dec 5, 2014 at 13:31
  • 2
    @maxmackie - There is a difference between the syntax you can use, and the actual type. An array is not a pointer, and a pointer is not an array. Yes, you can use array/pointer syntax to get to the various elements, but the types are not the same. Commented Dec 5, 2014 at 13:39

2 Answers 2

6

No, 'foo' is an array type in both cases but when a pointer is expected in expression with 'foo', it's implicitly converted to one (which points to the array first element). All arrays have this behavior. In the case, as addition can be done via pointer types, but not with arrays, 'foo' is converted to 'int *'.

*(foo+2) // 'foo' is implicitly converted into 'int *', pointing to 'foo' first element

foo + 1 //same as above

But now you may ask, what are the properties of the 'array' type and why we should ever use it, instead of the implicit pointer to first element cast. The things is that they are not much. You can tell the size of an object with type array like this:

sizeof(foo) //returns the size which array 'foo' occupies 

And get it's address by using the '&' operator:

&foo // '&foo' has type of 'int (*)[5]'

You can also create functions with parameters of 'array' reference (or pointer) type in order to accept only ones with specified size (which is not possible if they are just pointers and expect arrays passed to decay into such). Example:

void func(int (&)[5]);

void func1(int (*arg)[5]); // should be accessed by '*arg', allow the use of null-pointers

void func2(int *); //same as the misleading 'void func2(int [5])' or 'void func2(int [6])' etc.

int foo[5];

int foo1[6];

func(foo); // 'foo' type is ('int [5]') - ok

func1(&foo); // '&foo' type is ('int (*)[5]') - ok

func(foo1); // 'foo1' type is ('int [6]') - not allowed, param type is 'int (&)[5]' !

func1(&foo1); // '&foo1' type is ('int (*)[6]') - not allowed, param type is 'int (*)[5]' !

func2(foo); // 'foo' is implicitly converted to 'int *' - ok

func2(foo1); // 'foo1' is implicitly converted to 'int *' - ok

In the second case when the array is 2D - the same properties are applied. It's declaration means this: 'an array of 3 elements with type array of 4 elements with type int' So it's actually just an array of arrays and nothing more. It's implicit pointer to first element conversion is not of type 'int **' but instead of 'int (*)[4]', as each element of it is another array.

The declaration can be written this way too:

int (foo[3])[4];

Also note 'arrays' cannot be assigned, so they can't be passed by value or returned by functions. What I mean is:

int funcReturningArray()[2]; //not allowed

int funcAcceptingArray(int [2]); //just converted into pointer

int funcAcceptingArray(int *); //same as above

Although array parameters are syntactically accepted because of legacy reasons (or because something else ?), their real meaning is never tolerated and they are just 'adjusted' to pointers.

Note: The implicit conversion of array type to a pointer of it's first element is sometimes called 'Array to pointer decay'.

Sign up to request clarification or add additional context in comments.

2 Comments

Generally correct answer, but it could be improved: 1. You should probably say that the array decays into a pointer instead of "it's implicitly casted to one". The word cast usually implies that the programmer forces the compiler to do something against its better knowledge, not that something implicitly and effortlessly changes type under the hood. You could also improve the readability of the large code block significantly by drastically shortening the comments. Something like: //error: wrong type or //ok: foo decays into int*.
decay is the keyword. Should put that in the beginning
-3

No arrays are not pointers but in expressions they are converted to rvalue pointer to their first elements. So in this expression

*(foo+2)

at first foo is converted to rvalue pointer and then the pointer arithmetic is used.

For this array declaration

int foo[3][4];

name foo used in expressions is converted to rvalue pointer of type int ( * )[4]

The word rvalue means that for example you may not write ++foo

That is the compiler for the array name used in expressions creates a temporary object that is a poimnter to the first element of the array.

Take into account that if you are using for example operator sizeof with an array name then the last will not be converted to a pointer. So for your last array definition

sizeof( foo )

will be equivalent to

3 * 4 * sizeof( int )

while

sizeof( int ( * )[4] )

will return the size of the pointer itself.

And at last if you will apply operator & to an array name then you will get a pointer to the array itself. For example

int foo[3][4];

int ( *ptr_to_foo )[3][4] = &foo;

2 Comments

I really don't understand who downvoted this answer, it's perfectly correct!
"That is the compiler for the array name used in expressions creates a temporary object that is a poimnter to the first element of the array." Parse error...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.