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]
Related
So I've recently come across something that isn't really intuitive to me and got me a little confused. If I allocate an array on the heap like this:
uint32_t* Array = new uint32_t[5];
and then try to add a certain amount of bytes to the array pointer like this:
Array + 3
the result is going to be Array + sizeof(uint32_t) * 3 instead of Array + 3.
Why is this being done?
Additive operators (§7.6.6/4) [expr.add]/4:
When an expression J that has integral type is added to or subtracted
from an expression P of pointer type, the result has the type of P.
If P evaluates to a null pointer value and J evaluates to 0, the
result is a null pointer value.
Otherwise, if P points to element x[i] of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤ n and the expression P - J points to the (possibly-hypothetical) element *x[i − j] if 0 ≤ i − j ≤ n.
Otherwise, the behavior is undefined.
Subscripting (§7.6.1.1/1) [expr.sub]/1
A postfix expression followed by an expression in square brackets is a
postfix expression. One of the expressions shall be a glvalue of type
“array of T” or a prvalue of type “pointer to T” and the other shall
be a prvalue of 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)),
except that in the case of an array operand, the result is an lvalue
if that operand is an lvalue and an xvalue otherwise. The expression
E1 is sequenced before the expression E2.
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.
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;
Consider the following simple example computing lenght of an array:
#include <iostream>
int a[] = {1, 2, 4};
int main(){ std::cout << sizeof(a)/sizeof(a[0]) << std::endl; }
DEMO
The Standard N4296::8.3.4/7 [dcl.array]
If E is an n-dimensional array of rank i×j×. . .×k, then E appearing
in an expression that is subject to the array-to-pointer conversion
(4.2) is converted to a pointer to an (n−1)-dimensional array with
rank j ×. . .×k.
N4296::4.2/1 [conv.array]
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 what is the expressions which are the subject of the convertion? Looks like unevaluated operands are not the subject.
http://coliru.stacked-crooked.com/a/36a1d02c7feff41c
I know of the following expressions in which an array is not converted/decayed to a pointer.
When used in a sizeof operator: sizeof(array)
When used in an addressof operator: &array
When used to bind a reference to an array: int (&ref)[3] = array;.
When deducing the typename to be used for instantiating templates.
When used in decltype: decltype(array)
I don't know if anyone can name all the rules off the top of their head, so a community wiki may be appropriate.
The array to pointer conversion occurs in the following contexts. All references are to the C++11 standard.
As part of an implicit conversion sequence selected by overload resolution1
As part of a standard conversion sequence, in contexts where one is allowed
When initializing an object of non-class type from an array ([dcl.init]/16)2
When assigning to an lvalue of non-class type from an array ([expr.ass]/3)
When a prvalue of pointer type is required as the operand to a built-in operator ([expr]/8)
When subscripting into the array ([expr.sub]/1)
When dereferencing a pointer ([expr.unary.op]/1)
With the unary + operator ([expr.unary.op]/7)
With the binary + operator ([expr.add]/1)
With the binary - operator ([expr.add]/2)
With the relational operators ([expr.rel]/1)
With the equality operators ([expr.eq]/1)
When calling a function, if an argument has array type and is passed to an ellipsis ([expr.call]/7)
When converting from a pointer to base class to a pointer to derived class ([expr.static.cast]/11)
In a reinterpret cast to a non-reference type ([expr.reinterpret.cast]/1)
In a const cast to a non-reference type ([expr.const.cast]/1)
In the second or third operand of the conditional operator, under certain circumstances ([expr.cond])
In a template argument, if the corresponding (non-type) template parameter has pointer to object type ([temp.arg.nontype]/5)
The array to pointer conversion does not occur in the following contexts:
Where an lvalue (or glvalue) is required
By the unary & operator ([expr.unary.op]/3)
In a static cast to reference type ([expr.static.cast]/2, [expr.static.cast]/3)
In a reinterpret cast to reference type ([expr.reinterpret.cast]/11)
In a const cast to reference type ([expr.const.cast]/4)
When binding to a reference to the same array type
In a discarded-value expression ([expr]/10)
In the operand to sizeof ([expr.sizeof]/4)
When the second and third operands to the conditional operator have the same array type and are both glvalues of the same value category
In either operand to the built-in comma operator
1 This includes the case where an array of T is passed to a function expecting cv T*, cv void*, or bool, when a user-defined conversion requires one of those types, etc.
2 This includes contextual conversions to bool as they occur in if statements and the like.
The rule of thumb I work by is "in any part of an expression that produces a value result that can be stored in a pointer but cannot be stored in an array".
So, for example;
The expression array + 0 converts array to a pointer before doing the addition, and gives a result that is a pointer.
f(array) converts array to a pointer before calling the function f() that accepts a pointer or an array (not a reference).
array[0] is not required to convert array to a pointer (but the
compiler is free to, since it makes no difference on the result of that expression).
sizeof array does not convert array to a pointer (since it doesn't
evaluate array at all, just its size)
The expression p = array converts array to a pointer and that value
is stored in p
I'm sure there are some cases I've missed, but that simple rule works reasonably well. Of course, it is based on an understanding of what an expression is.....
In your example code, a[0] is identical to *(a + 0), and is thus subject to array-to-pointer conversion. See the Built-in subscript operator section here.
In C, array subscription: a[b] is merely the syntactic sugar equivalent of dereferencing after pointer arithmetic: *(a+b) (as explained, say, here).
How is array subscription interpreted in C++, for base types? (Not for classes, for which we have overload semantics)? And, more specifically, what type does C++ expect to appear as the subscript? Is it a ptrdiff_t?
How is array subscription interpreted in C++,
In C++ E1[E2] is identical to *((E1)+(E2))
what type does C++ expect to appear as the subscript?
C++ expects a unscoped enumeration or integral type both items are covered in the draft C++ standard section 5.2.1 Subscripting paragraph 1 which says (emphasis mine):
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.62 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 ]
As James points out, the wording One of the expressions shall have allows the pointer and subscript to be interchanged, for example:
#include <iostream>
int main()
{
int arr[5] = {1, 2, 3, 4, 5 } ;
std::cout << arr[2] << ":" << 2[arr] << std::endl ;
}
Using the alternative syntax 2[arr] is not recommended, most people won't know what this is doing it makes the code less readable and hence less maintainable.
which is similar to the relevant section in the draft C99 standard 6.5.2.1 Array subscripting paragraph 2 which says(emphasis mine):
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).
C++ is exactly the same as C in this respect. C++11 §5.2.1:
The expression E1[E2] is identical (by definition) to *((E1)+(E2))