Изменить указатель на массив, чтобы получить определенный элемент массива - PullRequest
6 голосов
/ 20 сентября 2008

Я понимаю общее значение указателей и ссылок (или, по крайней мере, я так думаю), я также понимаю, что когда я использую new , я динамически распределяю память.

У меня следующий вопрос:

Если бы я использовал cout << &p, он отображал бы «расположение виртуальной памяти» p. Есть ли способ, которым я мог бы манипулировать этим «местоположением виртуальной памяти?»

Например, следующий код показывает массив int s.

Если бы я хотел показать значение p[1], и я знал «расположение виртуальной памяти» p, мог бы я как-нибудь сделать «&p + 1» и получить значение p[1] с помощью cout << *p который теперь будет указывать на второй элемент в массиве?

int *p;
p = new int[3];

p[0] = 13;
p[1] = 54;
p[2] = 42;

Ответы [ 5 ]

8 голосов
/ 20 сентября 2008

Конечно, вы можете манипулировать указателем для доступа к различным элементам в массиве, но вам нужно будет манипулировать содержимым указателя (т.е. адресом, на который указывает p), а не адресом самого указателя .

int *p = new int[3];
p[0] = 13;
p[1] = 54;
p[2] = 42;

cout << *p << ' ' << *(p+1) << ' ' << *(p+2);

Каждое сложение (или вычитание) означает последующий (предыдущий) элемент в массиве. Если p указывает на 4-байтовую переменную (например, int на типичных 32-битных ПК) по адресу, скажем, 12345, p + 1 будет указывать на 12349, а не на 12346. Обратите внимание, что вы хотите изменить значение p содержит перед разыменованием его доступ к тому, на что он указывает.

3 голосов
/ 20 сентября 2008

Не совсем. &p - это адрес указателя p. &p+1 будет ссылаться на адрес, который на один int* дальше. Что вы хотите сделать, это

p=p+1; /* or ++p or p++ */

Теперь, когда вы делаете

cout << *p;

Вы получите 54. Разница в том, что p содержит адрес начала массива целых чисел , тогда как &p является адресом p . Чтобы переместить один элемент вперед, вам нужно указать дальше в массив int , а не дальше по вашему стеку, где находится p.

Если бы у вас было только &p, вам нужно было бы сделать следующее:

int **q = &p; /* q now points to p */
*q = *q+1;
cout << *p;

Это также выдаст 54, если я не ошибаюсь.

2 голосов
/ 20 сентября 2008

Мне нравится это делать:

&p[1]

Для меня это выглядит аккуратнее.

2 голосов
/ 20 сентября 2008

Прошло много времени (много лет) с тех пор, как я работал с указателями, но я знаю, что если p указывает на начало массива (т.е. p [0]) и вы увеличиваете его (то есть p ++), то теперь p указывая на p [1].

Я думаю, что вам нужно отменить ссылку p, чтобы получить значение. Вы разыменовываете указатель, помещая * перед ним.

Итак * p = 33 с изменением p [0] на 33.

Я предполагаю, что для получения второго элемента вы бы использовали * (p + 1), поэтому синтаксис, который вам понадобился бы, был бы:

cout << *(p+1)

или

cout << *(++p)
1 голос
/ 20 сентября 2008

Думайте о «типах указателей» в C и C ++ как о создании очень длинной логической строки ячеек , наложенной на байты в области памяти ЦП, начиная с байта 0. Ширина каждая ячейка в байтах зависит от «типа» указателя. Каждый тип указателя устанавливает строку с различной шириной ячейки. Указатель "int *" устанавливает ряд 4-байтовых ячеек, поскольку ширина памяти для int составляет 4 байта. "double *" устанавливает 8-байтовый ряд на ячейку; "struct foo *" указатель устанавливает строку с каждой ячейкой шириной "struct foo", что бы это ни было. «Адрес» любой «вещи» - это смещение байта, начиная с 0, ячейки в строке, содержащей «вещь».

Арифметика указателя основана на ячейках в строке, а не bytes."*(p+10)" - это ссылка на десятую ячейку после "p", где размер ячейки определяется типом p. Если тип "p" равен "int", адрес "p + 10" находится на 40 байтов после p; если p - указатель на структуру длиной 1000 байт, то "p + 10" - 10 000 байт после p. (Обратите внимание, что компилятор выбирает оптимальный размер для структуры, которая может быть больше, чем вы думаете; это происходит из-за «заполнения» и «выравнивания». Обсуждаемая 1000-байтовая структура может фактически занять 1024 байта на ячейку например, так что "p + 10" будет на самом деле на 10 240 байт после p.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...