В этом фрагменте кода я использую метод data() вектора для доступа к его элементам:
#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;
}
Который генерирует
myvector contains: 10 20 0 100 0
Вопрос в том, почему p[2] равен 0? Если предположить, что myvector.data() — это указатель на первый элемент (индекс 0), то p[0] — это 10, что нормально. ++p указывает на следующий элемент, который равен p[1] и равен 20, что тоже нормально. Теперь p[2] — следующий элемент после p[1]. Итак, последовательность должна быть 10 20 100. В чем здесь ошибка?
Вы перепутали myvector[2] и p[2]? Последний индексируется относительно самого p.
Попробуйте тот же код, но с массивом и указателем, и вы получите точно такой же результат.
p изначально был равен &myvector[0], но после приращения эквивалентен &myvector[1]. Таким образом, p[2] эквивалентно myvector[3]. Поскольку все элементы myvector были инициализированы нулями, а myvector[2] не изменилось, оно по-прежнему равно нулю.
Да, я перепутал это с моим вектором. Спасибо.
Также обратите внимание, что C++ не рекомендует вам выполнять (сложную) арифметику необработанных указателей. Метод данных обычно используется только для взаимодействия с устаревшими API, которым по-прежнему требуется необработанный указатель. В большинстве других кодов следует использовать итераторы или циклы for на основе диапазона.





Вы увеличили p на 1, а затем записали в p[2], что фактически теперь равно myvector[3].
Написание p[1] приведет к записи в поле, соседнем с *p.
Вы инициализируете указатель p, чтобы он указывал на myvector[0].
Затем вы увеличиваете p, и теперь оно указывает на myvector[1].
Если нарисовать, то это примерно так:
+-------------+-------------+-------------+-------------+-------------+
| myvector[0] | myvector[1] | myvector[2] | myvector[3] | myvector[4] |
+-------------+-------------+-------------+-------------+-------------+
^
|
p
Теперь важная часть: для любого указателя или массива p и индекса i выражение p[i] в точности равно *(p + i).
Это означает, что p[2] в вашем коде совпадает с *(p + 2). А поскольку p указывает на второй элемент вектора, p + 2 будет указывать на четвертый.
Еще раз нарисуем:
+-------------+-------------+-------------+-------------+-------------+
| myvector[0] | myvector[1] | myvector[2] | myvector[3] | myvector[4] |
+-------------+-------------+-------------+-------------+-------------+
^ ^ ^ ^
| | | |
p p + 1 p + 2 p + 3
Итак, когда вы пишете на p[2], это то же самое, что писать на myvector[3].
Согласно стандарту C++17 (подписка 8.2.1)
1 Постфиксное выражение, за которым следует выражение в квадратных скобках, постфиксное выражение. Одним из выражений должно быть значение glvalue введите «массив T» или значение типа «указатель на T», а другое должно быть значением перечисления без области действия или целочисленного типа. результат имеет тип «Т». Тип «Т» должен быть полностью определенным тип объекта. Выражение E1[E2] идентично (по определению) *((E1)+(E2)) [ Примечание: подробности о * и + см. в 8.3 и 8.7, а подробности о массивах — в 11.3.4. — конечное примечание] , за исключением того, что в случае операнда-массива результатом является lvalue, если этот операнд является lvalue и xvalue в противном случае. Выражение E1 секвенируется перед выражение Е2.
Итак, поскольку указатель p сначала указывает на первый элемент вектора, а затем после увеличения указателя p
++p;
*p = 20;
теперь он указывает на второй элемент вектора. И, наконец, выражение
p[2] в этом заявлении
p[2] = 100;
что эквивалентно выражению *( p + 2) дает четвертый элемент вектора.
Если перед этим оператором ввести промежуточный указатель
++p;
нравиться
int *q = p'
тогда выражение p[2], оцененное как *( p + 2 ), эквивалентно *( ( q + 1 ) + 2 ), то же самое, что *( q + 3 ). Таким образом, четвертый элемент вектора обновляется.
Давайте реорганизуем ваш код, чтобы p всегда указывал на первый элемент:
*p = 10;
//++p; // removed this line and replaced p with p+1 below
*(p+1) = 20;
(p+1)[2] = 100;
Далее, учтите, что a[b] для встроенного [] в точности эквивалентно *(a+b), следовательно, последняя строка *(p+1+2) is *(p+3) is p[3].
После того, как вы увеличили p один раз, индекс подписки будет соответствовать обновленному указателю. x[2] добавляет 2 к x, а затем разыменовывает его. Обычно x указывает на первый элемент массива, а ваш — на второй.
"++p points to the next element ...", а также увеличиваетpсебя.