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
Related
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);
#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
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);
Here are two lines of code:
int (*parry)[10] = &arr // Line # 1
int *(&arrRef)[10] = ptrs // Line # 2
Line # 1:
parry is a pointer that points to an int array of size 10.
So does it mean:
parray[1] points to the address of arr,
parray[2] points to address of arr
...
parray[10] points to address or arr?
When would I use Line # 1?
Solution:
#include <iostream>
int main(
{
int arr[10] = { 3, 54 };
int (*parry)[10] = &arr;
std::cout << (*parry)[0] << " " << (*parry)[1] << " " << (*parry)[3] << " " << parry[4] << std::endl;
return 0;
}
Output:
3, 54, 0, hex address of arr at index 4.
It seems like what inside parry[0] is a pointer that points to arr associated with the index. So, parry[0] ---> arr[0].
Line # 2:
arrRef is a reference to an int array of size ten pointers. arrRef is referred to by ptrs.
So does it mean:
arry[1] is an int pointer? ...
arry[10] is an int pointer?
What example can this been used in?
When in doubt, see the Clockwise/Spiral Rule.
int (*parry)[10] = &arr;
parry is a pointer to an array of 10 ints.
int *(&arrRef)[10] = ptrs;
arrRef is a reference to an array of 10 pointers to int.
Example:
int main()
{
int arr[10];
int* ptrs[10];
int (*parry)[10] = &arr;
int *(&arrRef)[10] = ptrs;
}
Now I've cleaned up your question, I can see it wasn't what I originally thought. You say:
parray is a pointer that points to an int array of size 10
so clearly you figured out the clockwise/spiral/cdecl stuff already.
So does it mean: ... parray[10] points to address of arr
Firstly, arrays in C++ are indexed starting from zero, so you can access arr[0] .. arr[9] if there are 10 elements; arr[10] would be the eleventh, so is out of bounds.
Now, let's take your sentence apart:
parray is a pointer
right, it isn't an array, it's a pointer. Now, let's consider what it is a pointer to:
an int array of size 10
ok, if it points to that, then *parray must be (a reference to) the original array.
So, (*parray)[0] is the first element of the array, etc.
Note that you can easily test your intuition about all this by just printing things out, and seeing what you get. You'll either see pointers, and be able to compare the addresses, or you'll see integer values, or you'll get (hopefully informative) compile errors. Try it out!
Oh, and:
When would I use line 1?
Only if you need to re-seat it, in general. For example, if you want to choose one of two different arrays based on some logic, and then ... perform further logic on whichever was selected.
Next, you said
arrRef is a reference to an int array of size ten pointers.
Correct!
arrRef is refer to by ptrs
No, arrRef refers to an array, the array has size 10, and its 10 elements are pointers-to-int. Note this is not the same type as the first array!
Since references can be used with the same syntax as the thing they refer to, we can use arrRef as an array.
So, arrRef[0] is the first element of the array, and it is a pointer-to-int.
What example can this been used in?
The only common reason for using reference-to-array is to avoid pointer decay, allowing templates to deduce the number of elements.
I think that in this statement
//line1// int (*parry)[10] = $arr
^^^ ^^
there is a typo
There must be
//line1// int (*parry)[10] = &arr;
^^^ ^^
It is assumed that arr is an array of type int[10]. For example
int arr[10];
And this declaration
int (*parry)[10] = &arr;
declares a pointer to this entire array.
As for this declaration
//line2// int *(&arrRef)[10] = ptrs;
^^^
then it is assumed that ptrs is an array of type int *[10] That is elements of the array have type int *. They are pointers.
And this declaration
int * (&arrRef)[10] = ptrs;
declares a reference to this array. A reference is in fact is an alias of an array.
In C++ 2014 you could define a reference to an array simpler.
For example
decltype( auto )arrRef = ( ptrs );
Here is a demonstrative program
#include <iostream>
int main()
{
int a[10];
decltype( auto )ra = ( a );
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( ra ) << std::endl;
ra[0] = 10;
std::cout << a[0] << std::endl;
std::cout << ra[0] << std::endl;
}
The program output is
40
40
10
10
For parsing C declarations it is valuable to remember, in the words of Kernighan and Ritchie, that "the syntax is an attempt to make the declaration and the use agree" (K&R, TCPL, 5.12). In other words, you can treat a declaration as an expression and simply apply the operators in the proper order. That will show you what type the declared identifier must have.
For example, in int (*parry)[10] you first apply the * operator, because it is in parentheses. This indicates that parray is a pointer. Then you apply the [] operator, indicating that the result of the dereferencing was an array; the 10 indicates the number of elements. The obtained element is of type int. Summing up: parray was a pointer to an array of int.
Declarations of references in C++ can not be solved that way because there is actually no operator which would create a reference, or dereference one; both operations are implicit in C++. The & symbol is used to signify references in declarations only (perhaps somewhat confusingly, because in expressions it's used to take an address). But if you think of the & in declarations as a * substitute to signify a reference instead of a pointer you should still be able to parse any declaration.
I am having a question in mind about c pointers to 2d array. We often write:
int (*p)[3]=a //here a is a 2d array
but writing as:
int (*p)[3]=a[0]
and
int (*p)[3]=&a[0]
produces the same result that is the base address of a. And if we cout p, it produces same result as *p.
Why this all is happening.
this is because array variables are basically addresses.so a[0] will point to the base address of the First 1D array because a itself is a 2D array.
This statement
int (*p)[3]=a[0]
is invalid and the compiler shall issue an error. The right operand has type int * while the left operand has type int (*p)[3]
These statements
int (*p)[3]=a
int (*p)[3]=&a[0]
are equivalent because array a in the right side is implicitly converted to pointer to its first element.
As for statements
std::cout << p;
and
std::cout << *p;
then they produce the same result because they output the address of the memort where the array is allocated. *p is equivalent to a[0] and implicitly converted to pointer to its first element that is &a[0][0]. So in both cases it is in fact the address of a[0][0] because arrays are placed in memory by rows starting from the first row.
First: your code is invalid since there are no casts between incompatible types.
Array names used in expressions on the right-hand side are implicitly converted to pointers to the first element of the array. This is what's going on:
#include <iostream>
using namespace std;
int main() {
int a[][2] = { {0,0}, {1,1}, {2,2}};
int (*p)[3]=(int(*)[3])a; // implicitly converted from array name to pointer to the first element (int(*)[2])
int (*p2)[3]=(int(*)[3])a[0]; // a[3][2], access a[0], an array, implicitly converted to int*
int (*p3)[3]=(int(*)[3])&a[0]; // Address of int[2] array, int(*)[2] type
cout << p << endl;
cout << p2 << endl;
cout << p3 << endl;
// your code goes here
return 0;
}
http://ideone.com/qG5riN