Array and base address redirection - c

int a[10];
printf("%p ", &a);
will display the address of array a.
So, if I perform a redirection, *(&a), why is that I don't get value stored at a[0]. What is the rule in C language that states I should be getting address of a. Yes, it does make sense, I get address of a, since * and & will cancel each other leading to simply a, which is the address of a.

int a[10];
printf("%p ", (void *) &a); // address of the array
printf("%p ", (void *) a); // adress of the first element of the array
printf("%p ", (void *) *(&a));// same as above
Here, the value of a is the same as &a[0]. And the value *&a is the same as the value of a when the a object is an array of int.
Note that the printed address will be the same as they both start at the same address.
I added the void * cast which is required as p requires a void * argument.

The C rule that governs this is C 2011 6.3.2.1 3: “Except when it is the operand of the sizeof operator, the _Alignof 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.”
a is an array of int. When you pass a to printf, the rule converts it to a pointer to int, and the value of that pointer is printed.
When you pass &a to printf: First, a is the operand of &, so the rule does not apply; a is not converted to a pointer to int; it remains an array of int. Second, the & is evaluated. &a yields the address of the array, and this address is printed. Since the address of the array is the same as the address of its first element, the address is printed.
Note that the type of the expression &a is “pointer to array of int”. So, when you have *&a, you are applying * to a pointer to an array of int, and the result is an array of int. Since the expression is an array of int, the rule applies, and this array of int is converted to a pointer to the first element, and the value of that pointer is printed.

The fact:
a[0] == *(a)
a[9] == *(a+9)

The type of the pointer that &a evaluates to is a pointer to an array (specifically a pointer to an int[10]). That's a different type that a pointer to the first element of the array, even if it's the same address.
printf("%d ", *&a[0]); will print the value of the first element of the array because &a[0] has type int*.

Related

the address for the array pointer, &array [duplicate]

This question already has answers here:
How come an array's address is equal to its value in C?
(6 answers)
Closed 7 years ago.
The following program prints that a and array share the same address.
How should I understand this behavior?
Is it &arr the address for the pointer arr, which contains the beginning address the 10 chars?
#include <stdio.h>
int main()
{
char arr[10] = {0};
char* a = (char*)(&arr);
*a = 1;
printf("a=%p,arr=%p.\n", a, arr);
printf("%d\n", arr[0]);
return 0;
}
When you allocate an array in C, what you get is something like the following:
+---+
arr[0]: | |
+---+
arr[1]: | |
+---+
...
+---+
arr[N-1]: | |
+---+
That's it. There's no separate memory location set aside for an object named arr to store the address of the first element of the array. Thus, the address of the first element of the array (&arr[0]) is the same value as the address of the array itself (&arr).
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.
So the type of the expression arr in the first printf call is char [10]; by the rule above, the expression "decays" to type char *, and the value is the address of arr[0].
In the expression &arr, arr is the operand of the unary & operator, so the conversion isn't applied; instead of getting an expression of type char **, you get an expression of type char (*)[10] (pointer to 10-element array of char). Again, since the address of the first element of the array is the same as the address of whole array, the expressions arr and &arr have the same value.
In idiomatic C, you should write char *a = arr; or char *a = &(arr[0]);. &arr is normally a char **. Even if modern (C++) compilers fixe it automatically, it is not correct C.
As arr is an array of char, arr[0] is a char and arr is the same as &(arr[0]) so it is a char *. It may be strange if you are used to other languages, but it is how C works. And it would be the same if arr was an array of any other type including struct.
The address printed out by arr and a is the memory address of the first element of the array arr. (Remember, the name of an array is always a pointer to the first element of that array.) This is because after you have defined the array arr, you define a as a pointer to the same address in memory.
According to the C Standard (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.
The address of an array is the address of its first element. So though these types are different
char ( * )[10] ( that corresponds to &arr ) and char *(that is used in the casting in statement
char* a = (char*)(&arr); ) they will have the same value that is the address of the first element of the array.
If you would not use the casting then the correct definition of the pointer initialized by expression &arr would be
char ( *a )[10] = &arr;
The difference is seen then the pointer is incremented. For your definition of pointer a the value of expression ++a will be greater sizeof( char) than the initial value . For the pointer I showed the value of expression ++a will be greater 10 * sizeof( char ) than the initial value.
In your case the type of expression *a is char and you may write *a = 1; while in my case the type of expression *a will be char[10] and you may not write *a = 1;

What does address of a, which is an array, returns?

I thought when you try to get the address of an array, it returns the address of the first element it holds.
int *j;
int a[5]={1,5,4,7,8};
Now j=&a[0]; works perfectly fine.
Even j=a also does the same function.
But when I do j=&a it throws an error saying cannot convertint (*)[5]' to int*' in assignment
Why does it happen? &a should be the first element of the array a, so it should give &a[0].
But instead it throws an error. Can somebody explain why?
The C standard says the following regarding how arrays are used in expressions (taken from C99 6.3.2.1/3 "Lvalues, array, and function designators):
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
This is commonly known as "arrays decay to pointers".
So the sub-expression a in the following larger expressions evaluates to a pointer to int:
j=&a[0]
j=a
In the simpler expression, j=a, that pointer is simply assigned to j.
In the more complex expression, j=&a[0], the 'index' operator [] is applied to the pointer (which is an operation equivalent to *(a + 0)) and the 'address-of' operator is applied to that, resulting in another pointer to int that gets assigned to j.
In the expression j=&a, the address-of operator is applied directly to the array name, and we hit one of the exceptions in the above quoted clause: "Except when it is the operand of ... the unary & operator".
Now when we look at what the standard says about the unary & (address-of) operator (C99 6.5.3.2/3 "Address and indirection operators"):
The unary & operator returns the address of its operand. If the
operand has type "type", the result has type "pointer to type".
Since a has type "array of 5 int" (int [5]), the result of applying & to it directly has type "pointer to array of 5 int" (int (*)[5]), which is not assignable to int*.
The type of a and &a is not the same even though they contain the same value, i.e., base address of the array a.
j = a;
The array name a here gets converted to a pointer to its first element.
Try to see what values you get via these statements to understand where the difference lies:
printf("%p", a+1);
printf("%p", &a+1);
c is a strongly typed language. Assignment such as j=a; is allowed only if j and a are of the same type or the compiler can safely convert a to j. In your case, type of j is int * while the type of &a is int (*)[5]. The compiler does not know how to automatically convert an object of type int (*)[5] to an object of type int *. The compiler is telling you exactly that.
a is an array of 5 ints. The pointer to a is a pointer to an array of five integers, or int (*)[5]. This is not compatible with an int * because of pointer arithmetic: If you increment a variable of type int *, the address in the variable increases by 4 (assuming 4 byte integers), so that it points to the next integer. If you increment a variable that points to an array of 5 integers, the address in the variable increases by 20 (again assuming 4 byte integers), so that it points to the next array of five integers.
Perhaps what's confusing is that the value give by a and &a is the same, as you said. The value is the same but the type is different, and the difference is most obvious when you do arithmetic on the pointers.
I hope that helps.

Does passing address to a pointer results in type promotion

While initializing the pointer p in the given statement
int a[10], *p;
p = &a[0];
I am in doubt that whether the type of &a[0] is pointer to int or is it int?
I came to this confusion after reading this:
Using a as a pointer to the first element in the array, we can modify a[0]: *a = 7;.
NOTE: I am interested to know the type of &a[0].
&a[0] is a pointer to int. Here are the interpretation steps for that:
&a[0] is parsed as &(a[0]) because the subscript operator [] binds more tightly than the address operator &.
a is an array, but it is automatically converted to a pointer to its first element in this case. (It would not be converted if it were the operand of sizeof, _Alignof, or & or were a string literal used to initialize an array.)
a[0] takes the pointer and becomes an lvalue for the first element (element 0).
&(a[0]) is a pointer to a[0]. Since we know a[0] is an int, a pointer to a[0] is a pointer to an int.
Then p is assigned the value of &a[0]. Thus, p is a pointer to the first element of a.
Since p is a pointer to the first element of a, *p is an lvalue for that element. An lvalue can be used on the left side of an assignment to assign to the object it refers to.
for historical reasons
p = a;
and
p = &a[0]
are equivalent. Beware that
auto q = &a;
is also legal but the type of q will NOT be int* but rather int[10] *. This is probably not what you wanted.
& is the address operator so, &a[0] is taking the address of the first element of the array a, so it is an int *. Since [] has higher precedence than * you can read it as follows:
&(a[0])
which may be more clear. The case where you have:
p = a ;
works do to the array decaying to a pointer.
The address of a[0] is of type pointer to an integer.
You can modify the first element of the array because *a is equivalent to *(a + 0) which is nothing but a[0].

Explanation of Array Pointers in c? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C: How come an array’s address is equal to its value?
C pointer : array variable
Considering a multidimensional Array:
int c[1][1];
Why all of the following expression points to the same address??
printf("%x", (int *) c); // 0x00000500
printf("%x", *c); // 0x00000500
printf("%x", c); // 0x00000500
How would a pointer's actual value and it's derefernced value can be the same?
Under most circumstances1, an expression of type "N-element array of T" will be converted ("decay") to expression of type "pointer to T", and the value of the expression will be the address of the first element in the array.
The expression c has type int [1][1]; by the rule above, the expression will decay to type int (*)[1], or "pointer to 1-element array of int", and its value will be the same as &c[0]. If we dereference this pointer (as in the expression *c), we get an expression of type "1-element array of int", which, by the rule above again, decays to an expression of type int *, and its value will be the same as &c[0][0].
The address of the first element of the array is the same as the address of the array itself, so &c == &c[0] == &c[0][0] == c == *c == c[0]. All of those expressions will resolve to the same address, even though they don't have the same types (int (*)[1][1], int (*)[1], int *, int (*)[1], int *, and int *, respectively).
1 - the exceptions to this rule are when the array expression is an operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration
You just have to think: where is the first position on this array?
Suppose it's on 0x00000050 in your memory space. What is the first item in your array? It's c[0][0], and its address is 0x00000050. Sure enough, the address of the first position is the same of the array. Even if you do c[0] only, it still points to the same address, as long as you cast it to the right type.
But you should not confuse pointers to arrays.
How would a pointer's actual value and it's derefernced value can be the same
It's not a pointer, it's an array.
See Q&A #3 & #4
c is the address of the array. c is also the address of the first element.

The value and address of an array are the same, except when passed to a function?

void pass_arr(int arr[]);
void pass_arr_test()
{
int arr[5] = {1,2,3,4,5};
printf( "arr = %p\n"
"&arr = %p\n\n", arr, &arr);
pass_arr(arr);
}
void pass_arr(int arr[])
{
printf( "passed arr = %p\n"
"passed &arr = %p\n\n", arr, &arr);
}
Output:
arr = 0x28ccd0
&arr = 0x28ccd0
passed arr = 0x28ccd0
passed &arr = 0x28ccc0
Can someone explain why the value and adress of arr points to the same adress when evaluated in the block where arr was created, but when passed the value and adress point to two different adresses?
That's because in the function arr is actually a pointer, not an array. Taking the address of a pointer does not yield the same address, the way it does for an array.
Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to type "pointer to T", and the value of the expression will be the address of the first element of the array1.
When you call
`pass_arr(arr)`;
the expression arr is converted from type "5-element array of int" to "pointer to int", or int *.
Note that the address of the first element of the array is the address of the array itself; that's why you get the same value when you print the results of arr and &arr int pass_arr_test, but remember that the types are different; the expression arr is converted to type int *, but &arr has type int (*)[5]; this matters for things like pointer arithmetic.
Secondly, in the context of a function prototype, declarations of the form T a[] and T a[N] are interpreted as T *a; a is actually declared as a pointer instead of an array.2
The important thing to remember is that arrays are not pointers. Rather, in most contexts, array expressions are converted to pointers as necessary.
1 - N1570, 6.3.2.1 Lvalues, arrays, and function designators, ¶ 3
2 - N1570, 6.7.6.3 Function declarators (including prototypes), ¶ 7
That is due to pass by value semantics where the arr in pass_arr method is a local pointer variable on the stack whose value is the location of the arr passed from pass_arr_test method. So, arr variable in both pass_arr and pass_arr_test are point to the same location and hence the value is same. Since they are two different pointers, their memory address is different. In case of array definition, arr is just an alias to the start of the array and hence it's location and it's value are the same.

Resources