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;
Related
Array returns pointer to the first element. I have simple code as below:
int a[10] = {1,2,3};//Filled three elements
int (*ptr)[10];//pointer to an array of 10 ints
ptr = a;
I am getting below warning.
warning: assignment from incompatible pointer type
If i modify the pointer definition as shown below then there is no warning
ptr = &a;
Why does the first assignment results in warning? Does &a returns integer pointer to array of 10 elements? Pls help to understand. Thanks
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.
Except for the sizeof, & and alignof operator, arrays decay to pointers.
int a[10] = {1,2,3};//Filled three elements
int (*ptr)[10];//pointer to an array of 10 ints
ptr = a;
In the assignment ptr = a, a decays to a pointer to int (int *), which points to the first element.
int a[10] = {1,2,3};//Filled three elements
int (*ptr)[10];//pointer to an array of 10 ints
ptr = &a;
Here &a is of type int (*)[10], which is a pointer to an array of 10 ints and has the same type as ptr. It is the proper way to assign a pointer to an array.
Also note that the value itself is the same for a and &a, the only difference is the type.
Here I have a 2D array. I want to declare a pointer to point to the first row of the array. First I did something like this
#include <stdio.h>
int main ()
{
int arr[2][2]={{6,2},{3,4}};
int *ptr=arr;
printf("%d",*(ptr+0));
}
First row of the 2D array is also a array. Similar type of pointer declaration for a 1D array don't give any warning. Why am I getting warning during compilation.
[Warning] initialization from incompatible pointer type [enabled by
default]
The following didn't give any warning
int main ()
{
int arr[2][2]={{6,2},{3,4}};
int (*ptr)[2]=arr;
printf("%d",*(ptr+0));
}
Except when it is the operand of the sizeof or unary & operators, 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.
In the line
int *ptr=arr;
the expression arr has type "2-element array of 2-element array of int" (IOW, T is "2-element array of int"). Since the expression arr is not the operand of either the sizeof or unary & operators, it is converted ("decays") to an expression of type "pointer to 2-element array of int", or int (*)[2], and the value of the expression is the address of the first element of the array.
This is why you got the warning for the line above, but not for
int (*ptr)[2]=arr;
since in that case the types match correctly.
Given the declaration
int arr[2][2]={{6,2},{3,4}};
the following are all true:
Expression Type Decays To Equivalent Value
---------- ---- --------- ----------------
arr int [2][2] int (*)[2] &arr[0][0]
&arr int (*)[2][2] &arr[0][0]
*arr int [2] int * &arr[0][0]
arr[i] int [2] int * &arr[i][0]
&arr[i] int (*)[2] &arr[i][0]
*arr[i] int arr[i][0]
arr[i][j] int
&arr[i][j] int *
So arr, &arr, arr[0], &arr[0], and &arr[0][0] all evaluate to the same value (the address of the first element of an array is the same as the address of the array itself), but the types are all different.
A very important point I want to get across (especially because it's shown up in a couple of other answers) is that array objects do not store any pointer values. If you looked at the contents of arr in memory, you'd see something like the following:
+---+
arr: | 6 | arr[0][0]
+---+
| 2 | arr[0][1]
+---+
| 3 | arr[1][0]
+---+
| 4 | arr[1][1]
+---+
No storage is set aside anywhere for any pointers. When your code is compiled, any expressions that refer to arrays are replaced with pointers to the first element of the array.
arr is an array of arrays of integers while ptr is a pointer to an integer. In an array of arrays you need two levels of indirection to reach an integer (arr[0][0]) while in a pointer you need just one (ptr[0]). You can assign an array of elements of a certain type to a pointer to an element of the same type, but not if the types are different which is the case here.
As you can see, they are two different things so the compiler does a good job on whining on your assignation.
2D arrays contain (as arrurri mentioned) a pointer which points to an array of pointers and each of those point to the actual elements. So, arr is a pointer to pointers and each indexed value of it (arr[i]) is a pointer to a row.
So, what you need to do is ptr=arr[0]; instead.
Kernighan & Ritchie 2nd ed. says:
The correspondence between indexing and pointer arithmetic is very close. By definition, the value of a variable or expression of type array is the address of element zero of the array. Thus after the assignment
pa = &a[0];
pa and a have identical values. Since the name of an array is a synonym for the location of the initial element, the assignment pa=&a[0] can also be written as
pa = a;
If a and pa are identical, then why this code:
#include <stdio.h>
int main()
{
char a[] = "hello";
char *pa = a;
printf("Array: %ld\n", sizeof(a));
printf("Pointer: %ld\n", sizeof(pa));
}
Outputs this:
Array: 6
Pointer: 8
Reference to an authoritative source would be much appreciated.
Two objects can have the same address but their sizes can be different.
From the C Standard (6.5.3.4 The sizeof and alignof operators)
2 The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand....
Consider the following example
#include <stdio.h>
int main( void )
{
struct A
{
char c;
int x;
} a;
printf( "object a:\taddress - %p size - %zu\n",
&a, sizeof( a ) );
printf( "object a.c:\taddress - %p size - %zu\n",
&a.c, sizeof( a.c ) );
}
The program output is
object a: address - 0x7fff164e16d0 size - 8
object a.c: address - 0x7fff164e16d0 size - 1
As it is seen the object a of type struct A and its data member c of type char have the same address but different sizes.
As for arrays then a pointer is an object that stores an address of other object. To store an address of other object it is enough to allocate for example 4 or 8 bytes of memory for the pointer depending on the used system.
As for arrays then they are named extents of memory. Arrays do not store addresses. They store their own elements (that of course can be pointers).
An array name used in expressions is converted to pointer to its first element.
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.
In this quote there is listed when an array is not converted to a pointer to its first element. For example when an array is the operand of sizeof operator.
If to return to your program
int main()
{
char a[] = "hello";
char *pa = a;
printf("Array: %ld\n", sizeof(a));
printf("Pointer: %ld\n", sizeof(pa));
}
then in this statement
char a[] = "hello";
string literal "Hello" that has type char[6] is not converted to a pointer.
However in this statement
char *pa = a;
array a is converted to pointer to its first element.
And in this statement
printf("Array: %ld\n", sizeof(a));
array a is not converted to a pointer because it is the operand of the sizeof operator.
However if you used an expression in the sizeof operator for example like this
sizeof( a + 0 )
then you would get a pointer and correspondingly the sizeof would return the size of the pointer instead of the size of the array
They do indeed have identical values. But that doesn't mean they are the same thing.
a is still a fixed-sized array. pa is still a pointer.
sizeof is one operator that recognises this difference.
Your array has 6 elements of size char (sizeof(char) is defined by the standard to be 1). (The 6th element is the string null terminator).
sizeof(char*) is 8 on your system. It's probably 64 bit.
Arrays are not pointers. The array name decays to a pointer to its first element in many cases, but sizeof is one of the few exceptions.
C11 §6.3.2.1 Lvalues, arrays, and function designators
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.
char a[] = "hello";
char *pa = a;
Here sizeof(a) will give size of array a . And sizeof(pa) will give size of pointer pa.Both are different .
Also as in function arguments array decays to pointer but this one is exception along with &.
Also while printing type size_t you should use specifier %zu (as specified in ANSI C99).
a and pa are not identical. Always remember: Arrays are not pointers. When used in an expression arrays are converted to pointer to its first element with some exception including as an operand of sizeof operator.
sizeof(a) will give the size of array while sizeof(pa) will give the size of pointer.
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.
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.