#include <iostream>
int main() {
int arr[2] = {1, 2};
int *p;
// p = &arr; // Does not compile
p = &arr[0]; // compiles
std::cout << "&arr = " << &arr << std::endl;
std::cout << "&arr[0] = " << &arr[0] << std::endl;
}
When I try to print the address both print the same address. But when I try to assign p = &arr it does not compile. Is there something in standard that says something against assigning address of array to pointer. I just wanted to know the reason why p = &arr does not compile?
Clang actually says error: cannot initialize a variable of type 'int *' with an rvalue of type
p = &arr;
is a compiler error because the type of &arr is int (*)[2] -- pointer to an "array of 2 ints". Hence, it cannot be assigned to p, whose type is int*.
Even though &arr and &arr[0] evaluate to the same numerical value, they are different types.
So you have this:
arr[0] is the first item in memory
arr[1] is the second item in memory
This is equivalent to the following:
*((int*)arr + 0) is the first item in memory
*((int*)arr + 1) is the second item in memory
"Dereference" the pointer, this lets you access the memory you want instead of the number which represents it in memory (the pointer):
*((int*)arr + 0)
This is equivalent to:
arr[0]
If you wanted the address of any item you can do as shown here:
(int*)arr + Index
The address of the first item is the memory address of the start of the array, so the address of the array AND the first item is:
(int*)arr + 0 or just (int*)arr
Your code here gets the address of the first item, which is the same as the address of the array:
p = &arr[0]; // compiles
Whenever you place an ampersand ( & ) its equivalent to getting the address of, so here you are getting [the address of the address of the array], this is not the same as the [address of the array]
p = &arr; // Does not compile
The type of the address of the address of the array is:
int (*)[2];
Not:
int *p;
That is why it doesn't compile, the types don't match.
To help with type related errors like this one you can use typeid and decltype, in C++ this lets you print the name of the type in question.
Like this
#include <iostream>
using namespace std;
int main()
{
int arr[2] = {1, 2};
std::cout<< "typeid ptr_array is " << typeid(decltype(&arr)).name() << "\n";
std::cout<< "typeid ptr_item is " << typeid(decltype(&arr[0])).name() << "\n";
return 0;
}
The result is:
ptr_array is PA2_i (Pointer to Array of size 2 with int)
ptr_item is Pi (Pointer to int)
"P" from typeid means pointer, "A" means array.
You can play around yourself here:
https://wandbox.org/permlink/RNNxjTMSUnLqUo6q
Related
int q[10]={0};
cout << q << endl;
cout << &q << endl;
cout << &q[0] << endl;
output is
0x7fffd4d2f860
0x7fffd4d2f860
0x7fffd4d2f860
Now when i do this->
int *r=q; // allowed
int *r=&q[0] // allowed
int *r=&q // not allowed
Why is the third assignment not allowed when it is essentially the same thing?
If you have an array declared like
T a[N];
where T is some type specifier then a pointer to the array will be declared like
T ( *p )[N] = &a;
A general rule is the following. If you have a multidimensional array (including one-dimensional arrays) like for example
T a[N1][N2][N3];
then this declaration you may rewrite like
T ( a[N1] )[N2][N3];
To get a pointer to the first element of the array just substitute the content in the parentheses the following way
T ( *p )[N2][N3] = a;
If you want to get a pointer to the whole array then rewrite the declaration of the array like
T ( a )[N1][N2][N3];
and make the substitution
T ( *p )[N1][N2][N3] = &a;
Compare this with a declaration of a scalar object and a pointer to it.
For example
T obj;
You may rewrite the declaration like
T ( obj );
Now to get a pointer to the object you can write
T ( *p ) = &obj;
Of course in this case the parentheses are redundant and the above declaration is equivalent to
T *p = &obj;
As for this code snippet
int q[10]={0};
cout << q << endl;
cout << &q << endl;
cout << &q[0] << endl;
and its output
0x7fffd4d2f860
0x7fffd4d2f860
0x7fffd4d2f860
then array designators used in expressions with rare exceptions are converted to pointers to their first elements.
So in fact the two expression q and &q[0] in these statements
cout << q << endl;
cout << &q[0] << endl;
are equivalent. On the other hand, the address of the array itself is the address of the memory extent that the array occupies. And in the beginning of the extent there is the first element of the array. So the three expressions give the same result: the address of the extent of memory occupied by the array.
Why is the third assignment not allowed when it is essentially the same thing?
Because The C++ language has a feature called "type safety". There is a type system that helps you keep the logic of your program sound.
One particular rule is that arbitrary pointer types can not be used to initialise pointers of other, incompatible types. In this case, you have a pointer to type int (.i.e. int*) that you try to initalise with an expression of type pointer to type array of 10 int (i.e. int(*)[10]). One type is not implicitly convertible to the other, hence the program is ill-formed.
Then why does cout print same things in all of the three cases?
Because all of the pointers have the same value. The first byte of the first element of the array is the same byte as the first byte of the entire array.
It just so happens that the stream insertion operator handles all pointer types1 exactly the same, so pointers with same value but different type produce the same output.
1 Pointers to character types are an exception. They are treated entirely differently.
Why can't we assign address of array to pointer?
Actually, we can assign address of an array to a pointer. We just cannot assign address of a array (or any other object for that matter) to a pointer of wrong type. We need a pointer to an array in this case:
int (*r)[10] = &q;
You cannot do the third assignment because &q's type is an int (*)[10], which is incompatible with the type of int* r.
The output of cout << &q does not reveal the type of &q. See this documentation link.
q is a fixed-length array. Specifying q by itself in an expression decays into a pointer to the 1st element of q. Thus, q decays to the same pointer value that &q[0] returns. &q, on the other hand, returns the memory address of the q variable itself, and for an array, its 1st element occupies that same memory address.
There is an operator<<(void*) defined for std::ostream, and void* can accept (almost) ANY type of pointer. Since all three of your cout calls resolve to the same memory address, and there is an operator<< that accepts all three types of pointers, that is why all three calls print the same number.
As for your assignments:
q is an int[10], which decays into an int*, which is why int *r=q; works.
&q[0] dereferences q to access its 1st element, which is an int, and then takes the address of that element, producing an int*, which is why int *r=&q[0]; works.
since q is an int[10], &q is an int(*)[10], which DOES NOT decay into an int*, which is why int *r=&q; does not work. You would have to declare r using the correct type:
int (*r)[10] = &q;
The following code demonstrates the differences between arr, &arr and &arr[0] where arr is an array of integers.
#include <iostream>
#include <string_view>
// Reference: https://stackoverflow.com/questions/81870/is-it-possible-to-print-a-variables-type-in-standard-c/56766138#56766138
// Type finding code start
template <typename T>
constexpr auto type_name()
{
std::string_view name, prefix, suffix;
#ifdef __clang__
name = __PRETTY_FUNCTION__;
prefix = "auto type_name() [T = ";
suffix = "]";
#elif defined(__GNUC__)
name = __PRETTY_FUNCTION__;
prefix = "constexpr auto type_name() [with T = ";
suffix = "]";
#elif defined(_MSC_VER)
name = __FUNCSIG__;
prefix = "auto __cdecl type_name<";
suffix = ">(void)";
#endif
name.remove_prefix(prefix.size());
name.remove_suffix(suffix.size());
return name;
}
// Type finding code end
int main()
{
int arr[5] = {1, 2, 3, 4, 5};
std::cout << "Value: " << arr << "\tType: " << type_name<decltype(arr)>() << std::endl;
std::cout << "Value: " << &arr << "\tType: " << type_name<decltype(&arr)>() << std::endl;
std::cout << "Value: " << &arr[0] << "\tType: " << type_name<decltype(&arr[0])>() << std::endl;
return 0;
}
See it in action.
Sample Output:
Value: 0x7ffcdadd22d0 Type: int [5]
Value: 0x7ffcdadd22d0 Type: int (*)[5]
Value: 0x7ffcdadd22d0 Type: int*
While all three are associated with the same memory location, they are of different types.
Reference: Is it possible to print a variable's type in standard C++?
This question already has answers here:
What is array to pointer decay?
(11 answers)
Passing the address of an array into a function in C++
(3 answers)
Why do the following have the same value: the pointer to an array, the dereferenced pointer to the array?
(3 answers)
How come an array's address is equal to its value in C?
(6 answers)
Closed 9 months ago.
I am a beginner to data structures and algorithms, started studying the pointers now and before asking the question here I read this recommended post but I couldn't understand it so I am asking the query here.
I have been told by a friend that array's name is a pointer to the first value in the array, as arr returns the address of arr[0], arr+1 returns address of arr[1], so when I write this
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i = 10;
int arr[3] = {1, 2, 3};
int *ptr = &i;
cout << arr << " " << &arr << endl;
cout << ptr << " " << &ptr;
return 0;
}
Both arr and &arr give same result
0x61ff00 0x61ff00
While ptr and &ptr give different results
0x61ff0c 0x61fefc
Can someone tell me why is this happening ?
Arrays are not pointers!
Arrays do decay to a pointer to their first element in all sorts of circumstances. For example std::cout << arr; actually prints the memory address of the first element of the array. std::cout << &arr; prints the memory address of the array. As the address of the first element is the same as the address of the array you see the same value.
However, just because they have the same value, does not mean they are the same. arr can decay to a int*, while &arr is a pointer to an array, a int(*)[3].
I hope the following will help to clear things up a little:
#include <iostream>
#include <type_traits>
void make_it_decay(int x[]) {
std::cout << std::is_same_v< decltype(x), int*> << "\n";
}
int main() {
int arr[3] = {1,2,3};
//std::cout << (arr == &arr) << "\n"; // does not compile !
std::cout << (arr == &(arr[0])) << "\n";
std::cout << std::is_same_v< decltype(arr), int[3]> << "\n";
std::cout << std::is_same_v< decltype(&arr),int(*)[3]> << "\n";
std::cout << std::is_same_v< decltype(&arr[0]), int* > << "\n";
make_it_decay(arr);
}
output:
1
1
1
1
1
I use decltype to infer the type of certain expressions and std::is_same_v to see if the expressions are of same type.
arr is of type int[3]. It is an array. It is not a pointer.
&arr is the address of the array. It is a pointer to an array with three elements, a int(*)[3].
&arr[0] even though it has the same value as &arr is of different type. It is a pointer to int, an int*.
When we pass arr to a function then it decays to a pointer to the first element of the array. And we can see that inside the function x is int*.
Now to your quesiton...
Above I tried to lay out what happens when you write std::cout << arr. Pointers are different, because ... well arrays are not pointers.
std::cout << ptr; // prints the value ptr
std::cout << &ptr; // prints the address of ptr
Perhaps some visualization helps. The difference in types gets most apparent when incrementing the pointers
-------------------
| arr |
-------------------
| 1 | 2 | 3 |
-------------------
^ ^ ^
&arr | &arr + 1
&arr[0] |
&arr[0] + 1
array's name is a pointer to the first value in the array
The above statement is not technically correct. What happens is that in many contexts the array decays to a pointer to its first element due to type decay. This means, in your example, when you wrote std::cout << arr, there was an implicit array-to-pointer conversion which converted your array arr of type int[3] to a pointer to its first element which is the type int*.
Note
Note also that even though the decayed pointer and the address of the array both have the same value their types are different. The decayed pointer is of type int* while the &arr is of type int (*)[3].
I wrote the next code:
int main()
{
int arr[] = {1,2,3,4,5};
std::cout <<"&arr: " <<&arr<<"\narr&:"<<&(arr+1);
return 0;
}
why is &arr compile and gives the address of arr at the position 0,
and &(arr+1) doesn't compile?
(I have expected it will return the address of arr at the position 1)
&arr is not an address "at a position", but the address of the entire array. You can see this via the difference in types:
&arr is the address of the array and has type ARR*, where ARR is the type int[5]. When combined, this type looks like int(*)[5].
&arr[0] is the address of the first element. It has type int*.
Now the actual values are the same because the array object starts at its first element, but it helps to not focus on that when trying to understand arrays vs. pointers.
When you say arr + 1, what's actually happening is that arr is being silently converted from an array (int[5]) to a pointer (int*) to the first element of the array. You then advance this pointer by one int. This results in an int* pointing to the second element of the array. This is the result you wanted to print and is equivalent to &arr[1].
Remember that & takes the address of an object. It's meaningless to take the address of a temporary like the pointer arr + 1. &(arr + 1) is equivalent to &(&arr[1]). They both try to take the address of something that logically doesn't have an address of its own. Remember that a pointer can store an address as its value, but the only reason & comes into play is because you can use it to obtain the address of an object, which can then be stored into a pointer. &ptr is the address of ptr itself, not the value stored in ptr.
In short, be consistent with what you want. Both of the following will print the address of the first element and the address of the second element. Both print two int*s since your intent is about individual elements, not the whole array:
std::cout << "First: " << &arr[0] << "\nSecond: " << &arr[1];
std::cout << "First: " << arr << "\nSecond: " << (arr + 1);
Can somebody explain to me why this code works?!!
I know A holds &A[0] and it is not a real pointer as if you cout<<&A you would get &A[0], but this result looks very strange to me.
int main()
{
double A[] = {2.4, 1.2, 4.6, 3.04, 5.7};
int len = *(&A+1) - A; // Why is this 5?
cout << "The array has " << len << " elements." << endl;
return 0;
}
And why this code doesn't work? And how can you make it work?
void test(double B[])
{
int len = *(&B+1) - B;
cout << len << endl;
}
int main()
{
double A[] = {2.4, 1.2, 4.6, 3.04, 5.7};
test(A);
system("pause");
return 0;
}
The expression is parsed like this:
(*((&A) + 1)) - A
The probably vexing part is that for some (but not all!) parts of this expression, the array decays to a pointer to the first element. So, let's unwrap this:
First thing is taking the address of the array, which gives you a pointer to an array of five elements.
Then, the pointer is incremented (+ 1), which gives the address immediately following the array.
Third, the pointer is dereferenced, which yields a reference to an array of five elements.
Last, the array is subtracted. It is only here that the two operands actually decay to a pointer to their first elements. The two are the length of the array apart, which gives the number of elements as distance.
&A takes the address of A itself. The type of A is double[5].
When you take the address of A itself and increment that pointer by 1, you are incrementing it by sizeof(double[5]) bytes. So now you have a pointer to the address following the A array.
When you dereference that pointer, you have a reference to the next double[5] array following A, which is effectively also a double* pointer to the address of A[5].
You are then subtracting the address of A[0] (an array decays into a pointer to its first element), and standard pointer arithmetic gives you 5 elements:
&A[5] - &A[0] = 5
This question already has answers here:
What is array to pointer decay?
(11 answers)
Closed 7 years ago.
I saw this code in this link-http://www.tutorialspoint.com/cplusplus/cpp_pointers_vs_arrays.htm. Look at the first piece of code.
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have array address in pointer.
ptr = var;
for (int i = 0; i < MAX; i++)
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the next location
ptr++;
}
return 0;
}
Shouldn't it be ptr = &var instead of ptr = var? It is below the comment. Why is it declared simply asvar instead of &var?
var will decay into a pointer to its first element.
ptr = var;
is equivalent to
ptr = &var[0];
&var is a pointer to an array, not to an int.
int (*aptr)[MAX] = &var;
would be valid, but it doesn't mean the same - *aptr is an array with MAX elements, not an int.
The tutorial's claim that "pointers and arrays are interchangeable in many cases" is completely wrong.
The only time you can "interchange" anything is this case; when something expects a pointer, an array decays into a pointer to its first element.
There is not a single case where you can use a pointer in place of an array.
Confusingly, ptr is often called "a pointer to an array" or even "an array" in informal conversation, even though this is formally incorrect.
This is because "a pointer to the first element of an array" is quite a mouthful, and to a non-beginner it's usually clear from context what is actually meant.
An array "decays" to a pointer to its first element in assignments, parameter passing etc. That would be a pointer to int, which is what p is declared as.
You actually can take the address of the array, although it is much less common. The address then is the address of the whole array, like this:
int (*parr)[3] = &var;
Now cou can say, for example, int i = (*parr)[1]; to initialize i with the second element of var, 100.
The address of the whole array is numerically identical with the address of its first element because the first element is where the array starts, after all. That may seem funny: What's the point then?
The difference is in type, which (apart from mere grammar questions about type compatibility -- but you can always cast those away in C!) determines what happens when you do pointer arithmetics. Consider
int *ptr = var;
int (*parr)[3] = &var;
printf("ptr: %p, parr: %p\n", ptr, parr);
printf("Increment ptr: %p, incremented parr: %p\n", ptr+1, parr+1);