Accessing elements with std::vector::data()

118 Views Asked by At

For this piece of code I am using the data() method of the vector to access its elements:

#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector (5);

  int* p = myvector.data();

  *p = 10;
  ++p;
  *p = 20;
  p[2] = 100;

  std::cout << "myvector contains:";
  for (unsigned i=0; i<myvector.size(); ++i)
    std::cout << ' ' << myvector[i];
  std::cout << '\n';

  return 0;
}

Which generates

myvector contains: 10 20 0 100 0

The question is why p[2] is 0? Assuming myvector.data() is a pointer to the first element (index 0), then p[0] is 10 which fine. ++p points to the next element which is p[1] and that is 20 which is also fine. Now, p[2] is the next element after p[1]. So, the sequence should be 10 20 100. Whats is the mistake here?

4

There are 4 best solutions below

0
ypnos On BEST ANSWER

You incremented p by 1 and then wrote into p[2], which effectively now is myvector[3].

Writing to p[1] would write to the field adjacent to *p.

0
Some programmer dude On

You initialize the pointer p to point to myvector[0].

Then you increment p, so now it points to myvector[1].

If we draw it out then it's something like this:

+-------------+-------------+-------------+-------------+-------------+
| myvector[0] | myvector[1] | myvector[2] | myvector[3] | myvector[4] |
+-------------+-------------+-------------+-------------+-------------+
                ^
                |
                p

Now the important part: For any pointer or array p and index i, the expression p[i] is exactly equal to *(p + i).

That means p[2] in your code is the same as *(p + 2). And since p is pointing to the second element of the vector, p + 2 will point to the fourth.

Again lets draw it out:

+-------------+-------------+-------------+-------------+-------------+
| myvector[0] | myvector[1] | myvector[2] | myvector[3] | myvector[4] |
+-------------+-------------+-------------+-------------+-------------+
                ^             ^             ^             ^
                |             |             |             |
                p             p + 1         p + 2         p + 3

So when you write to p[2] then it's the same as writing to myvector[3].

0
Vlad from Moscow On

According to the C++17 Standard (8.2.1 Subscripting)

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)) [ Note: see 8.3 and 8.7 for details of * and + and 11.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. The expression E1 is sequenced before the expression E2.

So as the pointer p initially points to the first element of the vector then after incrementing the pointer p

++p;
*p = 20;

it now points to the second element of the vector. And at last the expression p[2] in this statement

p[2] = 100;

that is equivalent to the expression *( p + 2 ) yields the forth element of the vector.

If to introduce an intermediate pointer before this statement

++p;

like

int *q = p'

then you have that the expression p[2] evaluated like *( p + 2 ) is equivalent to *( ( q + 1 ) + 2 ) that is the same as *( q + 3 ). So the fourth element of the vector is updated.

0
463035818_is_not_an_ai On

Lets refactor your code to make p always point to the first element:

*p = 10;
//++p;  // removed this line and replaced p with p+1 below
*(p+1) = 20;
(p+1)[2] = 100;

Next, consider that a[b] for built in [] is exactly equivalent to *(a+b), hence the last line is *(p+1+2) is *(p+3) is p[3].

After you incremented p once, the subsript index is with respect to the updated pointer. x[2] adds 2 to x and then dereferences it. Usually x points to first element of an array, but yours points to the second.