简体   繁体   中英

difference between pointer to an array and pointer to the first element of an array

int (*arr)[5] means arr is a pointer-to-an-array of 5 integers. Now what exactly is this pointer?

Is it the same if I declare int arr[5] where arr is the pointer to the first element?

Is arr from both example are same? If not, then what exactly is a pointer-to-an-array?

Theory

First off some theory (you can skip to the "Answers" section but I suggest you to read this as well):

int arr[5]

this is an array and "arr" is not the pointer to the first element of the array. Under specific circumstances (ie passing them as lvalues to a function) they decay into pointers : you lose the ability of calling sizeof on them.

Under normal circumstances an array is an array and a pointer is a pointer and they're two totally different things.

When dealing with a decayed pointer and the pointer to the array you wrote, they behave exactly the same but there's a caveat: an array of type T can decay into a pointer of type T, but only once (or one level-deep). The newly created decayed type cannot further decay into anything else.

This means that a bidimensional array like

int array1[2][2] = {{0, 1}, {2, 3}};

can't be passed to

void function1(int **a);

because it would imply a two-levels decaying and that's not allowed (you lose how elements of the array are laid out). The followings would instead work:

void function1(int a[][2]);
void function1(int a[2][2]);

In the case of a 1-dimensional array passed as lvalue to a function you can have it decayed into a simple pointer and in that case you can use it as you would with any other pointer .


Answers

Answering your questions:

int (*arr)[5]

this is a pointer to an array and you can think of the "being an array of 5 integers" as being its type, ie you can't use it to point to an array of 3 integers.

int arr[5]

this is an array and will always behave as an array except when you pass it as an lvalue

int* ptrToArr = arr;

in that case the array decays (with all the exceptions above I cited) and you get a pointer and you can use it as you want.

And: no, they're not equal otherwise something like this would be allowed

int (*arr)[5]
int* ptrToArr = arr; // NOT ALLOWED

Error cannot convert ‘int (*)[5]’ to ‘int*’ in initialization

they're both pointers but the difference is in their type.

At runtime, a pointer is a "just a pointer" regardless of what it points to, the difference is a semantic one; pointer-to-array conveys a different meaning (to the compiler) compared with pointer-to-element

When dealing with a pointer-to-array, you are pointing to an array of a specified size - and the compiler will ensure that you can only point-to an array of that size.

ie this code will compile

int theArray[5];
int (*ptrToArray)[5];
ptrToArray = &theArray;    // OK

but this will break:

int anotherArray[10];
int (*ptrToArray)[5];
ptrToArray = &anotherArray;    // ERROR!

When dealing with a pointer-to-element, you may point to any object in memory with a matching type. (It doesn't necessarily even need to be in an array; the compiler will not make any assumptions or restrict you in any way)

ie

int theArray[5];
int* ptrToElement = &theArray[0];  // OK - Pointer-to element 0

and..

int anotherArray[10];
int* ptrToElement = &anotherArray[0];   // Also OK!

In summary, the data type int* does not imply any knowledge of an array, however the data type int (*)[5] implies an array, which must contain exactly 5 elements.

A pointer to an array is a pointer to an array of a certain type. The type includes the type of the elements, as well as the size. You cannot assign an array of a different type to it:

int (*arr)[5]; 
int a[5];
arr = &a; // OK
int b[42];
arr = &b; // ERROR: b is not of type int[5].

A pointer to the first element of an array can point to the beginning of any array with the right type of element (in fact, it can point to any element in the array):

int* arr; 
int a[5];
arr = &a[0]; // OK
int b[42];
arr = &b[0]; // OK
arr = &b[9]; // OK

Note that in C and C++, arrays decay to pointers to the type of their elements in certain contexts. This is why it is possible to do this:

int* arr; 
int a[5];
arr = a; // OK, a decays to int*, points to &a[0]

Here, the type of arr ( int* ) is not the same as that of a ( int[5] ), but a decays to an int* pointing to its first element, making the assignment legal.

Pointer to array and pointer to first element of array both are different. In case of int (*arr)[5] , arr is pointer to chunk of memory of 5 int . Dereferencing arr will give the entire row. In case of int arr[5] , arr decays to pointer to first element. Dereferencing arr will give the first element.
In both cases starting address is same but both the pointers are of different type.

Is it the same if i declare int arr[5] where arr is the pointer to the first element? is arr from both example are same? if not, then what exactly is a pointer to an array?

No. To understand this see the diagram for the function 1 :

void f(void) {
    int matrix[4][2] = { {0,1}, {2,3}, {4,5}, {6,7} };
    char s[] = "abc";
    int i = 123;
    int *p1 = &matrix[0][0];
    int (*p2)[2] = &matrix[0];
    int (*p3)[4][2] = &matrix;
    /* code goes here */
}

在此处输入图片说明

All three pointers certainly allow you to locate the 0 in matrix[0][0] , and if you convert these pointers to 'byte addresses' and print them out with a %p directive in printf() , all three are quite likely to produce the same output (on a typical modern computer). But the int * pointer, p1 , points only to a single int , as circled in black. The red pointer, p2 , whose type is int (*)[2] , points to two int s, and the blue pointer -- the one that points to the entire matrix -- really does point to the entire matrix. These differences affect the results of both pointer arithmetic and the unary * (indirection) operator. Since p1 points to a single int , p1 + 1 moves forward by a single int . The black circle 1 is only as big as one int , and *(p1 + 1) is just the next int, whose value is 1. Likewise, sizeof *p1 is just sizeof(int) (probably 4).

Since p2 points to an entire 'array 2 of int', however, p2 + 1 will move forward by one such array . The result would be a pointer pointing to a red circle going around the {2,3} pair. Since the result of an indirection operator is an object, *(p2 + 1) is that entire array object, which may fall under The Rule. If it does fall under The Rule, the object will become instead a pointer to its first element, ie, the int currently holding 2 . If it does not fall under The Rule -- for instance, in sizeof *(p2 + 1) , which puts the object in object context -- it will remain the entire array object. This means that sizeof *(p2 + 1) (and sizeof *p2 as well, of course) is sizeof(int[2]) (probably 8).


1 Above content has been taken from More Words about Arrays and Pointers .

The address of the whole array, and the address of the first element, are defined to be the same, since arrays in C++ (and C) have no intrinsic padding besides that of the constituent objects.

However, the types of these pointers are different. Until you perform some kind of typecast, comparing an int * to an int (*)[5] is apples to oranges.

If you declare arr[5] , then arr is not a pointer to the first element. It is the array object. You can observe this as sizeof( arr ) will be equal to 5 * sizeof (int) . An array object implicitly converts to a pointer to its first element.

A pointer to an array does not implicitly convert to anything, which may be the other cause of your confusion.

If you write int arr[5] , you are creating an array of five int on the stack. This takes up size equal to the size of five ints.

If you write int (*arr)[5] , you are creating a pointer to an array of five int on the stack. This takes up size equal to the size of a pointer.

If it is not clear from the above, the pointer has separate storage from the array, and can point at anything, but the array name cannot be assigned to point at something else.

See my answer here for more details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM