Мое личное мнение таково, что картинки со стрелками, указывающими так или иначе, затрудняют понимание указателей. Это делает их похожими на некоторые абстрактные, таинственные сущности. Они не.
Как и все остальное в вашем компьютере, указатели являются числами . Название «указатель» - это просто причудливый способ сказать «переменная, содержащая адрес».
Поэтому позвольте мне все перемешать, объяснив, как на самом деле работает компьютер.
У нас есть int
, у него есть имя i
и значение 5. Это хранится в памяти. Как и все, что хранится в памяти, ему нужен адрес, иначе мы не сможем его найти. Допустим, i
заканчивается по адресу 0x12345678 и его приятель j
со значением 6 заканчивается сразу после него. Предполагая, что 32-битный процессор, где int составляет 4 байта, а указатели - 4 байта, переменные сохраняются в физической памяти следующим образом:
Address Data Meaning
0x12345678 00 00 00 05 // The variable i
0x1234567C 00 00 00 06 // The variable j
Теперь мы хотим указать на эти переменные. Мы создаем один указатель на int int* ip1
и один int* ip2
. Как и все в компьютере, эти переменные-указатели также размещаются в памяти. Предположим, что они заканчиваются на следующих соседних адресах в памяти, сразу после j
. Мы устанавливаем указатели для хранения адресов ранее выделенных переменных: ip1=&i;
(«скопировать адрес i в ip1») и ip2=&j
. Что происходит между строк:
Address Data Meaning
0x12345680 12 34 56 78 // The variable ip1(equal to address of i)
0x12345684 12 34 56 7C // The variable ip2(equal to address of j)
Итак, мы получили всего лишь 4 байтовых блока памяти, содержащих числа. Там нет мистических или магических стрел нигде в поле зрения.
Фактически, просто глядя на дамп памяти, мы не можем определить, содержит ли адрес 0x12345680 int
или int*
. Разница в том, как наша программа использует содержимое, хранящееся по этому адресу. (Задача нашей программы - просто сказать процессору, что делать с этими числами.)
Затем мы добавляем еще один уровень косвенности с int** ipp = &ip1;
. Опять же, мы просто получаем кусок памяти:
Address Data Meaning
0x12345688 12 34 56 80 // The variable ipp
Шаблон кажется знакомым. Еще один фрагмент из 4 байтов, содержащий число.
Теперь, если бы у нас был дамп памяти вышеупомянутого вымышленного небольшого ОЗУ, мы могли бы вручную проверить, куда указывают эти указатели. Мы посмотрим, что хранится по адресу ipp
переменной, и найдем содержимое 0x12345680. Который, конечно, адрес, где ip1
хранится. Мы можем перейти по этому адресу, проверить его содержимое и найти адрес i
, а затем, наконец, мы можем перейти по этому адресу и найти номер 5.
Поэтому, если мы возьмем содержимое ipp, *ipp
мы получим адрес переменной указателя ip1
. Написав, *ipp=ip2
мы копируем ip2 в ip1, это эквивалентно ip1=ip2
. В любом случае мы бы получили
Address Data Meaning
0x12345680 12 34 56 7C // The variable ip1
0x12345684 12 34 56 7C // The variable ip2
(Эти примеры были приведены для процессора с прямым порядком байтов)
ipp
при определении, чтобы ваш вопрос был