Измените указатель на массив, чтобы получить определенный элемент массива
Вопрос
Я понимаю общий смысл указателей и ссылок (или, по крайней мере, я так думаю), я также понимаю, что когда я использую новый Я динамически распределяю память.
Мой вопрос заключается в следующем:
Если бы я использовал cout << &p
, он отобразит «местоположение виртуальной памяти» p
.Есть ли способ манипулировать этой «виртуальной памятью»?
Например, следующий код показывает массив int
с.
Если бы я хотел показать ценность p[1]
и я знал «локацию виртуальной памяти» p
, мог бы я как-нибудь сделать"&p + 1
" и получить значение p[1]
с cout << *p
, который теперь будет указывать на второй элемент массива?
int *p;
p = new int[3];
p[0] = 13;
p[1] = 54;
p[2] = 42;
Решение
Конечно, вы можете манипулировать указателем для доступа к различным элементам массива, но вам нужно будет манипулировать содержимым указателя (т.адрес того, на что указывает p), а не адрес самого указателя.
int *p = new int[3];
p[0] = 13;
p[1] = 54;
p[2] = 42;
cout << *p << ' ' << *(p+1) << ' ' << *(p+2);
Каждое сложение (или вычитание) означает последующий (предыдущий) элемент массива.Если p указывает на 4-байтовую переменную (например. интервал на типичных 32-битных ПК) по адресу, скажем, 12345, p+1 будет указывать на 12349, а не на 12346.Обратите внимание, что вы хотите изменить значение того, что содержит p, прежде чем разыменовывать его, чтобы получить доступ к тому, на что он указывает.
Другие советы
Не совсем. &p
это адрес указателя p
. &p+1
будет ссылаться на адрес, который является одним int*
дальше.То, что вы хотите сделать, это
p=p+1; /* or ++p or p++ */
Теперь, когда ты это делаешь
cout << *p;
Вы получите 54.Разница в том, p
содержит адрес начала массива целых чисел, пока &p
это адрес п.Чтобы переместить один элемент вперед, вам нужно указать дальше в целочисленный массив, а не дальше по вашему стеку, где p
жизни.
Если бы у тебя был только &p
тогда вам нужно будет сделать следующее:
int **q = &p; /* q now points to p */
*q = *q+1;
cout << *p;
Это также выведет 54, если я не ошибаюсь.
Прошло много времени (много лет) с тех пор, как я работал с указателями, но я знаю, что если p указывает на начало массива (т.е.p[0]), и вы увеличили его (т.е.p++), то p теперь будет указывать на p[1].
Я думаю, что вам нужно отменить ссылку на p, чтобы получить значение.Вы разыменовываете указатель, помещая перед ним *.
Итак, *p = 33 с заменой p[0] на 33.
Я предполагаю, что для получения второго элемента вы должны использовать *(p+1), поэтому синтаксис вам понадобится:
cout << *(p+1)
или
cout << *(++p)
Мне нравится делать это:
&p[1]
По мне так аккуратнее выглядит.
Думайте о «типах указателей» в C и C++ как о очень длинном и логическом описании. ряд ячеек накладывается на байты в пространстве памяти ЦП, начиная с байта 0.Ширина каждой ячейки в байтах зависит от «типа» указателя.Каждый тип указателя устанавливает строку с разной шириной ячеек.А "int *"
Указатель размещает строку из 4-байтовых ячеек, поскольку ширина хранения целого числа составляет 4 байта.А "double *"
устанавливает 8-байтовую строку на ячейку;а "struct foo *"
указатель устанавливает строку, каждая ячейка которой имеет ширину одной ячейки. "struct foo"
, что бы это ни было.«Адрес» любой «вещи» — это смещение в байтах, начиная с 0, ячейки в строке, содержащей «вещь».
Арифметика указателей основана на ячейках в строке, а не на байтах. "*(p+10)
« — это ссылка на 10-ю ячейку после «p», где размер ячейки определяется типом p.Если тип «p» — «int», адрес «p+10» находится на 40 байт дальше p;если p — указатель на структуру длиной 1000 байт, «p+10» — это 10 000 байт после p.(Обратите внимание, что компилятор должен выбрать оптимальный размер структуры, который может быть больше, чем вы думаете;это связано с «заполнением» и «выравниванием».Например, обсуждаемая структура размером 1000 байт может фактически занимать 1024 байта на ячейку, поэтому «p+10» на самом деле будет на 10 240 байт дальше p.)