If i want to initialize a pointer to an int to an array, i need to use this notation:
int data[] = {34,35,36};
int *ptr = &data[0];
because the type of the variable data is int[], that's the reason why the next declaration gives warnings:
int *ptr = &data;
In the case above I'm assigning an "array type" to an int pointer, it's a mistake and is ok. So, why is it possible to use the next code to iterate in the array:
for(int i=0;i<3;i )
*(data i);
What the line above should do is to add the size of the full array in every iteration and the correct code should be as shown below:
for(int i=0;i<3;i )
*(&data[0] i);
but if we test them, both are equals and correct to iterate in the array.
So, the type of the variable data (alone, without []) should be thought as int[] or int? how can i know when a variable will have one type or another to do correct pointer aritmethic.
CodePudding user response:
From the C Standard (6.5.2.1 Array subscripting)
2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1) (E2))). Because of the conversion rules that apply to the binary operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).
And (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
Thus in this expression
*(data i)
the array data is implicitly converted to a pointer to its first element. And the expression is equivalent to data[i] or i[data].
So the expression
*(&data[0] i);
can be rewritten like
*(&*( data 0 ) i);
that is the same as
*( data 0 i);
and in turn as
*( data i);
Also in the declaration of a pointer
int *ptr = &data[0];
you could just write
int *ptr = data;
CodePudding user response:
Ok. After reading your comments i discovered the concept "array decay".
The name of an array naturally decays into a pointer to the type of the array; for example, if i declare int data[5], the type of data will be int* most of the times, but there are some exceptions to this decay. There are more information abut it here: exceptions to array decaying
My confussion got from that: sometimes when i used an array, it decayed and other times it didn't.
CodePudding user response:
In most cases whenever an array name is used in an expression, it decays into a pointer to it's first element. Therefore int *ptr = &data[0]; is 100% equivalent to int *ptr = data;.
As for accessing individual items of an array, or of an array pointed at through a pointer to the first element, arr[i] is 100% equivalent to *(arr i), the latter is just needlessly hard to read. See Do pointers support "array style indexing"?
However, one exception to the mentioned array decay rule is when an array name is used as operand to the & operator. In that case it does not decay - instead we get a pointer to "the array as whole". In your case int *ptr = &data; is an invalid pointer conversion because &data is of type int(*)[3], a pointer to array.
Please note however that in the expression &data[i], operator precedence says that [] "binds tighter" to the data operand than &. So it is equivalent to &(data[i]). The previously mentioned exception to array decay does not apply, since the & is never applied to the array name, but to an item in the array. Array decay into a pointer to the first element has already happened when we reach &, since it happened at the point where [] was encountered.
