C++, Use [] notation on pointer? - c++

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;

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 this pointer to an array expression work

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

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.

In C++, do dereferencing and getting index zero do the same tihng?

I just tried this code:
int i = 33;
int * pi = &i;
cout << "i: " << *pi << endl;
cout << "i: " << pi[0] << endl;
Both lines return the same thing.
Essentially, if I get index zero of any pointer, I'll get the value of the correct type at the location of the pointer. Isn't that the same thing as dereferencing?
Every time a pointer is dereferenced in C++, wouldn't getting index zero also work? I'm not suggesting anyone should actually do that, but I think it would work. Wouldn't it?
Ignoring overloaded operators, there's one case there is a difference, and that's array rvalues post-DR1213:
using arr = int[2];
arr&& f();
int&& b = *f(); // error, *f() is an lvalue, doesn't bind to int&&
int&& c = f()[0]; // OK, subscript applied to array rvalue results in an xvalue
I don't know of any compiler that implements that resolution, though. But it should be implemented eventually.
Assuming no operator overloading, they are nearly the same.
[C] 6.5.2.1 Array subscripting:
E1[E2] is identical to (*((E1)+(E2)))
[C++] 5.2.1 Subscripting:
The expression E1[E2] is identical (by definition) to *((E1)+(E2)) ... , except that in the case of an array operand, the result is an
lvalue if that operand is an lvalue and an xvalue otherwise.
See the great answer of #T.C regarding the last part.
For pointers, they should give the same result.
The only time that they could differ is if you are applying them on a user-defined type that overloads operator*() and operator[](int) differently (or one and not the other, in which case you would get a compile error).

C++ Pointer Arithmetics

Given the code:
int arr[] = {11,22,33,44,55}
for(int i = 0; i <5 ; i++)
cout << *(arr+i) << " ";
Does *(arr+i) have the same effect as arr[i]?
Yes. In fact, the subscript operator E1[E2] is defined as equivalent to *((E1)+(E2)):
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)).
yes. array are decayed to pointers. Array name points to first element of array. So
*(arr +i)
is equivalent to:
arr[i]