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.
As a beginner programmer I am dealing with some simple problems related to Pointers. In the following code I found the value of *a and a are same in hexadecimal. But I can't understand the reason.
#include <stdio.h>
#include <stdlib.h>
main(){
int a[5][5];
a[0][0] = 1;
printf("*a=%p a=%p \n", *a, a);
return 0;
}
Here is the output:
*a=0x7ffddb8919f0 a=0x7ffddb8919f0
An array and its first element have the same address.:)
For this declaration
int a[5][5];
expression a used in the printf call is implicitly converted to the pointer to its first element. Expression *a yields the first element of the array that is in turn a one-dimensional array that also is converted to a pointer to its first element.
Thus expressions a and *a have the same value as expression &a[0][0]
In C and C++ languages values of array type T [N] are implicitly converted to values of pointer type T * in most contexts (with few exceptions). The resultant pointer points to the first element of the original array (index 0). This phenomenon is informally known as array type decay.
printf argument is one of those contexts when array type decay happens.
A 2D array of type int [5][5] is nothing else than an "1D array of 1D arrays", i.e. it is an array of 5 elements, with each element itself being an array of 5 ints.
The above array type decay rule naturally applies to this situation.
The expression a, which originally has array type int [5][5], decays to a pointer of type int (*)[5]. The pointer points to element a[0], which is the beginning of sub-array a[0] in memory. This is the first pointer you print.
The expression *a is a dereference operator applied to sub-expression a. Sub-expression a in this context behaves in exactly the same way as before: it decays to pointer of type int (*)[5] that points to a[0]. Thus the result of *a is a[0] itself. But a[0] is also an array. It is an array of int[5] type. It is also subject to array type decay. It decays to pointer of type int *, which points to the first element of a[0], i.e. to a[0][0]. This is the second pointer you print.
The reason both pointer values are the same numerically is that the beginning of sub-array a[0] corresponds to the same memory location as element a[0][0].
a can be considered a pointer to a pointer to an int (in reality, it's an array of array of int, but close enough).
So a and *a both point to the same address (which happens to be a[0][0]).
*a is still a pointer, and a[0] is the same address as a[0][0].
Related
Here is the context:
int *t[10];
int n;
I am being told that t-n is of the type int**.
I don't exactly get what int** means, is it a pointer of a pointer? Why would the subtraction of a table of pointers - int would give a pointer of pointer of an int? When we refer to *t[0] do we refer to int* p to the pointer itself because it is an element of the table or do we implicitly need a pointer to point at the slot than have the pointer point to the another place?
Thanks in advance for explaining this to me.
I don't exactly get what int** means, is it a pointer of a pointer?
Yes.
int = integer
int * = pointer-to-integer
int ** = pointer-to-(pointer-to-integer)
int *** = pointer-to-(pointer-to-(pointer-to-integer))
(and so on)
Why would the subtraction of a table of pointers - int would give a
pointer of pointer of an int?
Because in C (and C++), an array decays into a pointer to the first item when necessary. For example, int *t[10] is an array of 10 pointer-to-int items. t can decay into a pointer to t[0], ie a pointer-to-(pointer-to-int), int **. That pointer can then be used for pointer arithmetic (like subtraction).
So, subtracting n from t would give you an int ** that is pointing n items "before" the beginning of your 10-item array (which BTW would not be a safe pointer to use, unless n was zero or a small negative number, since it would be pointing outside the valid bounds of the array's memory).
When we refer to *t[0] do we refer to int* p to the pointer itself
because it is an element of the table or do we implicitly need a
pointer to point at the slot than have the pointer point to the
another place?
I'm not sure I understand this question. Since t[10] is an array of 10 pointers (i.e. 10 int *'s), that means that t[0] is a single item in that array and therefore has type int *. Therefore *t[0] dereferences the first pointer in the array, yielding the actual int value that the pointer is pointing to.
what int** means
It's the type of a pointer to a pointer to an int. If you dereference a variable t of this type (like this: *t), you get a pointer to an int. If you dereference it twice (like this: **t), you get an int.
If you have TYPE a[N];, the array expression a, if evaluated, produces a pointer of type T *, pointing to a[0]. This is sometimes called C's array-to-pointer "decay" rule.
If TYPE is int *, as in your case, then TYPE * is int **.
Since your array is of int * pointers, the pointer which indexes into the array is a necessarily pointer to that element type.
e.g.
int arr[2][3] = ...
The type of arr[0] is
int (*)[3] // pointer to int[3], which is a pointer.
Or
int[3] // an array whose size is 3, which is an array.
Google tells me nothing about the question.
I know pointer and array are different types(derived types).
Maybe C and C++ treat it differently, I hope to see standard wording.
arr[0] is of type int [3] which is not a pointer.
int (*p)[3] is of type int(*)[3] meaning pointer to an array of 3 elements.
Pointer is not array and array is not pointer.
Now when you pass this 2d array to a function (or any case where decaying occurs) then it decays into pointer to the first element which is int (*)[3].
To be more clear in C 2d array is nothing but array of arrays.
Dissecting
arr is an array each of element of which is again an array with 3 elements.
arr[0] in most of the cases (except sizeof etc) will decay into pointer to first element it contains which is an int*.
arr[0][0] is an int.
At last &arr[0] .. guess what? This is of type int(*)[3].
As far as I know, multidimensional array on stack will occupy continuous memory in row order. Is it undefined behavior to index multidimensional array using a pointer to elements according to ISO C++ Standard? For example:
#include <iostream>
#include <type_traits>
int main() {
int a[5][4]{{1,2,3,4},{},{5,6,7,8}};
constexpr auto sz = sizeof(a) / sizeof(std::remove_all_extents<decltype(a)>::type);
int *p = &a[0][0];
int i = p[11]; // <-- here
p[19] = 20; // <-- here
for (int k = 0; k < sz; ++k)
std::cout << p[k] << ' '; // <-- and here
return 0;
}
Above code will compile and run correctly if pointer does not go out of the boundary of array a. But is this happen because of compiler defined behavior or language standard? Any reference from the ISO C++ Standard would be best.
The problem here is the strict aliasing rule that exists in my draft n3337 for C++11 in 3.10 Lvalues and rvalues [basic.lval] § 10. This is an exhaustive list that does not explicetely allow to alias a multidimensional array to an unidimensional one of the whole size.
So even if it is indeed required that arrays are allocated consecutively in memory, which proves that the size of a multidimensional array, say for example T arr[n][m] is the product of is dimensions by the size of an element: n * m *sizeof(T). When converted to char pointers, you can even do arithmetic pointer operations on the whole array, because any pointer to an object can be converted to a char pointer, and that char pointer can be used to access the consecutive bytes of the object (*).
But unfortunately, for any other type, the standard only allow arithmetic pointer operations inside one array (and by definition dereferening an array element is the same as dereferencing a pointer after pointer arithmetics: a[i] is *(a + i)). So if you both respect the rule on pointer arithmetics and the strict aliasing rule, the global indexing of a multi-dimensional array is not defined by C++11 standard, unless you go through char pointer arithmetics:
int a[3][4];
int *p = &a[0][0]; // perfectly defined
int b = p[3]; // ok you are in same row which means in same array
b = p[5]; // OUPS: you dereference past the declared array that builds first row
char *cq = (((char *) p) + 5 * sizeof(int)); // ok: char pointer arithmetics inside an object
int *q = (int *) cq; // ok because what lies there is an int object
b = *q; // almost the same as p[5] but behaviour is defined
That char pointer arithmetics along with the fear of breaking a lot of existing code explains why all well known compiler silently accept the aliasing of a multi-dimensional array with a 1D one of same global size (it leads to same internal code), but technically, the global pointer arithmetics is only valid for char pointers.
(*) The standard declares in 1.7 The C++ memory model [intro.memory] that
The fundamental storage unit in the C++ memory model is the byte... The memory available to a C++ program consists of one or more sequences of contiguous bytes. Every
byte has a unique address.
and later in 3.9 Types [basic.types] §2
For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object
holds a valid value of type T, the underlying bytes making up the object can be copied into an array
of char or unsigned char.
and to copy them you must access them through a char * or unsigned char *
I believe the behavior in your example is technically undefined.
The standard has no concept of a multidimensional array. What you've actually declared is an "array of 5 arrays of 4 ints". That is a[0] and a[1] are actually two different arrays of 4 ints, both of which are contained in the array a. What this means is that a[0][0] and a[1][0] are not elements of the same array.
[expr.add]/4 says the following (emphasis mine)
When an expression that has integral type is added to or subtracted from a pointer, the result has the type
of the pointer operand. If the pointer operand points to an element of an array object, and the array is
large enough, the result points to an element offset from the original element such that the difference of
the subscripts of the resulting and original array elements equals the integral expression. In other words, if
the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P))
and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array
object, provided they exist. Moreover, if the expression P points to the last element of an array object,
the expression (P)+1 points one past the last element of the array object, and if the expression Q points
one past the last element of an array object, the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to elements of the same array object, or one past
the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is
undefined
So, since p[11] expands to *(p + 11) and since p and p + 11 are not elements of the same array (one is an element of a[0] and the other is more than one element past the end of a[0]), the behavior of that addition is undefined.
I would, however, be very surprised to find any implementation where such an addition resulted in anything other than the one you expect.
if you declare
int arr[3][4][5];
the type of arr is int[3][4][5], type of arr[3] is int[4][5], etc. Array of array of arrays, but NOT an array of pointers. Let's see what happens if we increment first index? It would shift pointer forward by size of array element, but array element of arr is a two-dimensional array! It is equivalent to incrementing: arr + sizeof(int[4][5])/sizeof(int) or arr + 20.
Iterating this way we'll find that arr[a][b][c] equals to *(*(*(arr + a) + b) + c), provided that there is never any padding with arrays (to comply with mandatory compatibility of POD types with C99):
*((int*)arr + 20*a + 5*b + c)
When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
pointer operand points to an element of an array object, and the array
is large enough, the result points to an element offset from the
original element such that the difference of the subscripts of the
resulting and original array elements equals the integral expression
Let's say i have a 2 D array int m[3][4]
If the typedef is defined as
typedef int array[4];
array *ptr = m;
What does this mean? Is it pointer to array of 4 elements. Or array of 4 pointers?
When we cout << ptr or cout << *ptr, It prints the same address. How is that possible?
ptr is pointer to an array of four elements of type int. m is an array of 3 elements of type (of array of four elements of type int). To give you a picture - m is an array of 3 elements of type array. And that is the reason when ptr is initialized to m - there is no problem because 'm' being an array is implicitly converted to pointer to first element in that array.
ptr is pointer to an array of elements. So that pointer is printed. And when *ptr is used - you get an array which again get's implicitly converted to pointer to the first element of the array, which again is the same starting point - so you get the same value.
As everything starts at the same point you are getting the same value. Thing will start differentiating when one does ++ on pointers. I will leave you with that.
Check out the clockwise/spiral rule. After reading this you can read the declaration as being a pointer to the type-alias array, in other words a pointer to an array of four integers.
As per "clockwise/spiral rule" ptr is a pointer to array of 4 int.
I have been programming c/c++ for many years, but todays accidental discovery made me somewhat curious... Why does both outputs produce the same result in the code below? (arr is of course the address of arr[0], i.e. a pointer to arr[0]. I would have expected &arr to be the adress of that pointer, but it has the same value as arr)
int arr[3];
cout << arr << endl;
cout << &arr << endl;
Remark: This question was closed, but now it is opened again. (Thanks ?)
I know that &arr[0] and arr evaluates to the same number, but that is not my question! The question is why &arr and arr evaluates to the same number. If arr is a literal (not stored anyware), then the compiler should complain and say that arr is not an lvalue. If the address of the arr is stored somewhere then &arr should give me the address of that location. (but this is not the case)
if I write
const int* arr2 = arr;
then arr2[i]==arr[i] for any integer i, but &arr2 != arr.
#include <cassert>
struct foo {
int x;
int y;
};
int main() {
foo f;
void* a = &f.x;
void* b = &f;
assert(a == b);
}
For the same reason the two addresses a and b above are the same. The address of an object is the same as the address of its first member (Their types however, are different).
arr
_______^_______
/ \
| [0] [1] [2] |
--------------------+-----+-----+-----+--------------------------
some memory | | | | more memory
--------------------+-----+-----+-----+--------------------------
^
|
the pointers point here
As you can see in this diagram, the first element of the array is at the same address as the array itself.
They're not the same. They just are at the same memory location. For example, you can write arr+2 to get the address of arr[2], but not (&arr)+2 to do the same.
Also, sizeof arr and sizeof &arr are different.
The two have the same value but different types.
When it's used by itself (not the operand of & or sizeof), arr evaluates to a pointer to int holding the address of the first int in the array.
&arr evaluates to a pointer to array of three ints, holding the address of the array. Since the first int in the array has to be at the very beginning of the array, those addresses must be equal.
The difference between the two becomes apparent if you do some math on the results:
arr+1 will be equal to arr + sizeof(int).
((&arr) + 1) will be equal to arr + sizeof(arr) == arr + sizeof(int) * 3
Edit: As to how/why this happens, the answer is fairly simple: because the standard says so. In particular, it says (§6.3.2.1/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.
[note: this particular quote is from the C99 standard, but I believe there's equivalent language in all versions of both the C and C++ standards].
In the first case (arr by itself), arr is not being used as the operand of sizeof, unary &, etc., so it is converted (not promoted) to the type "pointer to type" (in this case, "pointer to int").
In the second case (&arr), the name obviously is being used as the operand of the unary & operator -- so that conversion does not take place.
The address is the same but both expressions are different. They just start at the same memory location. The types of both expressions are different.
The value of arr is of type int * and the value of &arr is of type int (*)[3].
& is the address operator and the address of an object is a pointer to that object. The pointer to an object of type int [3] is of type int (*)[3]
They are not the same.
A bit more strict explanation:
arr is an lvalue of type int [3]. An attempt to use
arr in some expressions like cout << arr will result in lvalue-to-rvalue conversion which, as there are no rvalues of array type, will convert it to an rvalue of type int * and with the value equal to &arr[0]. This is what you can display.
&arr is an rvalue of type int (*)[3], pointing to the array object itself. No magic here :-) This pointer points to the same address as &arr[0] because the array object and its first member start in the exact same place in the memory. That's why you have the same result when printing them.
An easy way to confirm that they are different is comparing *(arr) and *(&arr): the first is an lvalue of type int and the second is an lvalue of type int[3].
Pointers and arrays can often be treated identically, but there are differences. A pointer does have a memory location, so you can take the address of a pointer. But an array has nothing pointing to it, at runtime. So taking the address of an array is, to the compiler, syntactically defined to be the same as the address of the first element. Which makes sense, reading that sentence aloud.
I found Graham Perks' answer to be very insightful, I even went ahead and tested this in an online compiler:
int main()
{
int arr[3] = {1,2,3};
int *arrPointer = arr; // this is equivalent to: int *arrPointer = &arr;
printf("address of arr: %p\n", &arr);
printf("address of arrPointer: %p\n", &arrPointer);
printf("arr: %p\n", arr);
printf("arrPointer: %p\n", arrPointer);
printf("*arr: %d\n", *arr);
printf("*arrPointer: %d\n", *arrPointer);
return 0;
}
Outputs:
address of arr: 0x7ffed83efbac
address of arrPointer: 0x7ffed83efba0
arr: 0x7ffed83efbac
arrPointer: 0x7ffed83efbac
*arr: 1
*arrPointer: 1
It seems the confusion was that arr and arrPointer are equivalent. However, as Graham Parks detailed in his answer, they are not.
Visually, the memory looks something like this:
[Memory View]
[memory address: value stored]
arrPointer:
0x7ffed83efba0: 0x7ffed83efbac
arr:
0x7ffed83efbac: 1
0x7ffed83efbb0: 2
0x7ffed83efbb4: 3
As you can see, arrPointer is a label for memory address 0x7ffed83efba0 which has 4 bytes of allocated memory which hold the memory address of arr[0].
On the other hand, arr is a label for memory address 0x7ffed83efbac, and as per Jerry Coffin's answer, since the type of variable arr is "array of type", it gets converted to a "pointer of type" (which points to the array's starting address), and thus printing arr yields 0x7ffed83efbac.
The key difference is arrPointer is an actual pointer and has its own memory slot allocated to hold the value of the memory it's pointing to, so &arrPointer != arrPointer. Since arr is not technically a pointer but an array, the memory address we see when printing arr is not stored elsewhere, but rather determined by the conversion mentioned above. So, the values (not types) of &arrPointer and arrPointer are equal.