Why does this pointer to an array expression work - c++

I cannot understand why does this code work this way. I know that ptr is a pointer to an array of int and it points to the second “row” of arr.
int arr[][2] = { {1}, 2, 3};
int (*ptr)[2] = arr + 1;
cout << (**arr)[*ptr];
It prints 3 which is arr[1][1] but **arr is 1 and *ptr is memory address of arr[1][0].
Why does (**arr)[*ptr] return 3? Am I missing something here?

This declaration
int arr[][2] = { {1}, 2, 3};
declares an array of two elements of the type int[2].
This expression
(**arr)
gives the integer value 1.
This declaration
int (*ptr)[2] = arr + 1;
declares pointer to the second element of the array arr. So *ptr returns this second "row" of the array arr. Using in expressions like this
(**arr)[*ptr]
it is converted to pointer to its first element.
So you have an expression like
int[int *]
or
i[p]
where i is an integer value and p is a pointer.
That is equivalent to
int *[int]
or
p[i]
because according to the C++ Standard (or C Standard) the both are evaluated like
*( p + i )
So as **arr is equal to 1 and the the expression *ptr points to the first element of the second row then the result is the second element of the second row that is 3.
From the C++ 17 Standard (5.2.1 Subscripting)
1 A postfix expression followed by an expression in square brackets is
a postfix expression. One of the expressions shall have the type
“array of T” or “pointer to T” and the other shall have unscoped
enumeration or integral type. The result is of type “T.” The type “T”
shall be a completely-defined object type.64 The expression E1[E2]
is identical (by definition) to *((E1)+(E2)) [ Note: see 5.3 and 5.7
for details of * and + and 8.3.4 for details of arrays. — end note ],
except that in the case of an array operand, the result is an lvalue
if that operand is an lvalue and an xvalue otherwise.
That is if you have an array like this
T a[N];
where T is some type specifier when the expression
a[i]
is equivalent to
i[a]
provided that i represents a postfix expression.
Here is a demonstrative program.
#include <iostream>
int main()
{
int a[] = { 1, 2, 3, 4, 5 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t i = 0;
while ( i != N ) std::cout << i++[a] << ' ';
std::cout << '\n';
return 0;
}
Its output is
1 2 3 4 5

Related

Can we somehow use array[i] instead of *(array+i)?

In C++, when I have to use an array inside some function, I pass the array as an argument and get a pointer pointing to the first element of the array. While it is okay to use, and not much of a hassle to use a pointer, I was wondering if there exists some in-built header file, or any other set of instructions, by which when I want to access the i-th element of the array I can simply write array[i] and it gets read by the compiler as *(array+i)?
It would be great if one exists, since it would make it quite uniform and easy to code, since all the times when I use vectors I can access the i-th element just by vector[i] while in array I have to use it the other way *(array+i).
Also, is there some reason why the developers of C++ chose to return pointers to an array instead of the object itself?
If a is a pointer and i has an integral type, then a[i] is always the same as *(a+i). There is no need to include a header or anything to make it work.
I was wondering if there exists some in-built header file or any other set of instructions by which when I want to access the i-th element of the array I can simply write array[i] and it gets read by the compiler as *(array+i)
No, there is no such header or set of instructions, because it is part of the language.
For a pointer and an integral type, a[i] means *(a+i). This is such a strong statement that:
int base_array[3]={1,2,3}; // an array of 3 elements
int* ptr_array = base_array; // base_array "decays" to a pointer to the first element
std::cout << 2[ptr_array] << "\n"; // huh?!?!
prints 3, because *(2+ptr_array) is 3; ie, it even works backwards.
Can we somehow use array[i] instead of *(array+i)?
Yes, we can. Those expressions are practically identical. The subscript operator is much more readable, so I recommend using that.
I was wondering if there exists some in-built header file
You don't need to include any header.
while in array i have to use it the other way *(array+i)
Just because you can, doesn't mean that you have to. You don't have to use it the other way.
P.S. Besides arrays and vectors, we can also use the subscript operator with a pointer to element of an array.
Also, is there some reason why the developers of C++ chose to return pointers to an array instead of the object itself?
Because sometimes indirection is necessary or useful.
From the C++ 14 Standard (5.2.1 Subscripting)
1 A postfix expression followed by an expression in square brackets is
a postfix expression. One of the expressions shall have the type
“array of T” or “pointer to T” and the other shall have unscoped
enumeration or integral type. The result is of type “T.” The type “T”
shall be a completely-defined object type. The expression E1[E2] is
identical (by definition) to *((E1)+(E2)) [ Note: see 5.3 and 5.7
for details of * and + and 8.3.4 for details of arrays. — end note ],
except that in the case of an array operand, the result is an lvalue
if that operand is an lvalue and an xvalue otherwise.
So these expressions array[i] and *( array + i ) are evaluated the same way whether array in this expressions is an array designator or a pointer to first element of an array,
Moreover these expressions array[i] and i[array] are also evaluated the same way.
Arrays are non-modifianle lvalues so you may not return an array from a function. If to use an array designator in a return statement it will be converted to pointer to its first element. As a result arrays do not have the copy assignment operator.
On the other hand you can return a reference to an array provided that it doesn not have automatic storage duration.
For example
#include <iostream>
const size_t N = 5;
decltype( auto ) f( int ( &a )[N], int init )
{
for ( size_t i = 0; i < N; i++ )
{
a[i] = init++;
}
return a;
}
int main()
{
int a[N];
decltype( auto ) ra = f( a, 0 );
std::cout << sizeof( ra ) << '\n';
for ( const auto &item : ra )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
20
0 1 2 3 4

Why does the sizeof operator produce different results for an array

Why does the sizeof operator produces 12 bytes when it should only be 4? When I reference the variable array, that is only referring to the memory address of the first index of the array. In fact, I printed the memory address of the first index &array[0] and compared it to array, they produced the same memory address result which confirms that they are both referring to the first index of the array, but 'array' produces 12 byte while array[0] produces 4 byte.
int main() {
int array[] = {1,2,3};
int a = 1;
int b = sizeof(array); //this is referring to the first index of the array
int c = sizeof(array[0]); //this is also referring to the first index of the array
std::cout << b << std::endl;
std::cout << array << std::endl; //they have the same memory address
std::cout << &array[0] << std::endl; /* they have the same memory address, which confirms that array
and &array[0] is the same */
return 0;
}
Arrays and pointers are not the same, and this is a prime example of this.
In most contexts, an array decays to a pointer to its first member. One of the few times this decay does not happen is when the array is the subject of the sizeof operator. In that case it refers to the entire array and the expression evaluates to the size of the entire array in bytes.
This is described in section 6.3.2.1p3 of the C standard:
Except when it is the operand of the sizeof operator, the _Alignof operator, or theunary & 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.
As well as the C++11 standard in sections 7.2:
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The temporary materialization conversion (7.4) is applied. The result is a pointer to the first element of the array.
And 8.3.3p4:
The lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3) standard conversions are not applied to the operand of sizeof. If the operand is a prvalue, the temporary materialization conversion (7.4)is applied.
So what we actually have is:
int b = sizeof(array); // size of the entire array
int c = sizeof(array[0]); // size of the first element of the array
int d = sizeof(&array[0]); // size of a pointer to an array element
The size of the array is 12 bytes. The output is correct. The size of the element is 4 bytes. There are 3 elements. 4 * 3 = 12.
In fact, i printed the memory address of the first index (&array[0]) and compared it to (array), they produced the same memory address result which confirms that they are both referring to the first index of the array
Just because the array has the same memory address as the first element of the array, doesn't mean that the entire array is contained within the first element. It isn't.
then why does array+1 refers to the second index of the array?
Because in such a sub expression, the array is implicitly converted to a pointer to first element, and adding 1 to a pointer to first element results in a pointer to second element. Such implicit conversion is called decaying.
If I understand your question well, on 64 bit machine int will be 4 bytes so the sizeof operator will return 3 x 4 = 12 bytes. Did not understand your assumption why it should return 4 in first place when you allocated only three items in that array.
If you want to know the number of items in the array you may do something as follows:
// Finds size of array[] and stores in 'size'
int size = sizeof(array)/sizeof(array[0]);

passing pointers (the name of array) into function in C/C++

Lets say we create an array like:
int a[4]={1,2,3,4};
Now a is the name of this array and also the pointer points to the first element a[0]. So when I want to call the elements in the array, I can use a[ i ] or *(a+i).
Now I have a function:
void print_array(int* array, int arraySize){
for(int i=0; i<arraySize; i++){
cout<<*(array+i)<<endl;
cout<<array[i]<<endl;
}
}
When I pass a[4]={1,2,3,4} into this function using print_array(a,4), for the first line of cout, I fully understand because I use *(a+i) method to access data and a is the pointer I passed.
What I can't understand is: since I pass a pointer a into function, why can I use a in the format of a[i] like the second line of cout? Isn't a a pointer? If a is a pointer why does a[i] work?
This has confused me for a whole day. Any help will be much appreciated!
a is an array, not a pointer. They are not the same things. However, the name a can be implicitly converted to a pointer (with the value &a[0]).
For example;
int main()
{
int a[] = {1,2,3,4};
int *p = a; // p now has the value &a[0]
Now, after this partial code snippet, assuming i is an integral value, rules of the language amount to;
a[i] is equivalent to *(a + i) which is equivalent to *(&a[0] + i)
p[i] is equivalent to *(p + i)
Now, since p is equal to &a[0] this means that a[i], *(a + i), p[i], and *(p + i) are all equivalent.
When calling print_arrat(a, 4) where a is the name of an array, then a is ALWAYS converted to a pointer. This means print_arrat() is always passed a pointer. And this means *(array + i) inside print_arrat() is the same as a[i] in the caller.
This quote from the C++ Standard will make the point clear (5.2.1 Subscripting)
1 A postfix expression followed by an expression in square brackets is
a postfix expression. One of the expressions shall have the type
“array of T” or “pointer to T” and the other shall have unscoped
enumeration or integral type. The result is of type “T.” The type “T”
shall be a completely-defined object type.64 The expression E1[E2] is
identical (by definition) to *((E1)+(E2)) [Note: see 5.3 and 5.7 for
details of * and + and 8.3.4 for details of arrays. —end note], except
that in the case of an array operand, the result is an lvalue if that
operand is an lvalue and an xvalue otherwise.
Because in effect, while the subscript operator is defined on arrays, what happens is that they decay into pointers for the arithmetic to occur.
Meaning if a is an array, semantically what happens is:
int b = a[i]; => int *__tmp = a; int b = *(__tmp + i);
However, once operator overloading comes into play, then it is no longer true that a[i] == *(a + i). The right hand side may not even be defined.
What I can't understand is: since I pass a pointer "a" into function, why can I use "a" in the format of a[i] like the second line of "cout"?
Because subscript operator a[i] is defined for arrays and it is equivalent to *(a+i) by definition.
In the line with cout, you use array[i] however, where array is a pointer. This is also allowed, because the subscript operator is also defined for pointers.
Isn't "a" a pointer?
No. a is an array. array is a pointer.

Point to specific rows of 2-D arrays

I wrote the following code to point to first row of a 2-dimensional array. However, when I do
arrayPtr = & array[0];
I end up getting
error: cannot convert double (*)[1] to double* in assignment
arrayPtr = & array[0];
My program is:
#include <iostream>
int main(int argc, char **argv)
{
double array[2][1];
array[0][1] = 1.0;
array[1][1] = 2.0;
double* arrayPtr;
arrayPtr = &array[0];
return 0;
}
Can someone help me understand as to where am I going wrong?
Instead of arrayPtr = & array[0], you can write
arrayPtr = array[0];
to make use of array decay property.
Related,
Quoting C11, chapter §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. [...]
Quoting C++14, chapter §5.3.3
The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are not
applied to the operand of sizeof.
and, for chapter 4.2,
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue
of type “pointer to T”. The result is a pointer to the first element of the array.
So, while used as the RHS operand of the assignment operator, array[0] decays to the pointer to the first element of the array, i.e, produces a type double* which is the same as the LHS.
Otherwise, the use of & operator prevents the array decay for array[0] which is an array of type double [1].
Thus, &array[0] returns a type which is a pointer to an array of double [1], or, double (*) [1] which is not compatible with the type of the variable supplied in LHS of the assignment, a double *.
In your code:
array is of type double (*)[1];
array[0] is of type double[1]
&array[0] (this equals to array) is of type double (*)[1] (i.e. pointer to double[1])
Note 1: T[] can decay to T*. So in your example double[] can decay to double *.
Note 2: a[b] == *(a + b), so in your example &array[0] equals to & (*(array + 0)) which is simplified to array itself.
double array[2][1];
double* arrayPtr;
arrayPtr = & array[0];
arrayPtr has the type
POINTER (DOUBLE)
while array has the type
POINTER(POINTER(DOUBLE))
&array[0] has the type
POINTER(POINTER(DOUBLE))
You try to assign
POINTER (DOUBLE) <= POINTER(POINTER(DOUBLE))
The correct way to do it is
arrayPtr = array[0];
or
arrayPtr = *array;

C++, Use [] notation on pointer?

I just noticed I can use [] on a pointer and it works, but I was wondering, if this is good to use it.
int a[]={1,2,3,4};
int *p=&a[1];
std::cout << p[0]; // returns 2;
std::cout << p[-1]; // returns 1;
std::cout << p[1]; // returns 3;
I always learned, you have to use it like this:
std::cout << *(p-1);
std::cout << *(p+1);
But is it okay to use the operator [] on a pointer ?
In C/C++, given a pointer p and integral value k, p[k] is evaluated as *(p+k). Either form is fine to use as long as p+k points to valid memory.
If you have access to the C99 Standard, see section 6.5.2.1 Array subscripting, Paragraph 2. It says:
A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the
initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).
If you have access to the C++11 standard, see section 5.2.1 Subscripting, Paragraph 1. It says:
A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall have the type “pointer to T” and the other shall have unscoped enumeration or integral type.
The result is an lvalue of type “T.” The type “T” shall be a completely-defined object type. The expression E1[E2] is identical (by definition) to *((E1)+(E2))
In addition to great answer by R Sahu you can also do
std::cout << p[-1]; // returns 1;
std::cout << p[1]; // returns 3;
std::cout << 1[p]; // returns 3;
std::cout << (-1)[p]; // returns 1;
See : Ideone
For pointer p and integer value k :
p[k] and k[p] both are evaluating to *(p+k). So, both are same.
But following one is not same
std::cout << -1[p]; // returns -3;
std::cout << (-1)[p]; // returns 1;