Зачем нужны указатели?
Oбъяcнитe, зaчeм нyжны yкaзaтeли? Heт, я пoнял пpинцип paбoты, нo нe пoнял oднoгo — ЗAЧEM? Зaчeм paбoтaть c фyнкциями-члeнaми, пepeмeнными пo ccылкe, ecли я мoгy paбoтaть c ними нaпpямyю?
Отслеживать
51.6k 199 199 золотых знаков 59 59 серебряных знаков 242 242 бронзовых знака
задан 4 янв 2012 в 13:25
3,278 4 4 золотых знака 35 35 серебряных знаков 49 49 бронзовых знаков
Если Вы не поняли «зачем», значит Вы не поняли указатели!
4 янв 2012 в 13:28
Посмотрите, например, man qsort (это очень полезная функция сортировки), подумайте как это можно запрограммировать и многое прояснится.
4 янв 2012 в 13:59
qsort реализуется и без указателей. Например в таких языках как lisp/haskell, где указателей (по крайней мере в явном виде) нет. На плюсах можно без указателей тоже сделать, но только памяти будет больше потребляться.
4 янв 2012 в 14:20
Какой смысл биться за лишние сто байт памяти?
4 янв 2012 в 15:20
На самом деле все намного проще, указатели нужны для того чтобы писать «волшебные» коды, быстрые и непанятные. + для того чтобы те кто не знает С++ думали что С++ это что-то неимоверно сложное 😀 Использовать х надо потому, что в они есть и твой код становится более непонятным. **** PS:Как мне показалось — объяснил на вашем нынешнем уровне **** PPS:не трольте коммент ибо коммент сам по себе троллинг 😀
4 янв 2012 в 15:35
4 ответа 4
Сортировка: Сброс на вариант по умолчанию
«Если кто-то зажигает звезды, значит, это кому-нибудь нужно»
Вот такой пример. Положим, Вы передаете в функцию какую-то переменную. Там с ее значением что-то делается, и новое значение должно быть занесено в ту переменную, значение которой Вы в функцию передали. Если сделаете что-то типа этого
void func (int a) < a += 10; >. int i = 2; func(i);
То значение переменной i не изменится, потому что в функцию передается копия этой переменной и с ней производятся операции. А если передать указатель или ссылку на эту переменную, то получите доступ к ней и можете изменять ее значение
void func (int* a) < *a += 10; >. int i = 2; func(&i);
Если нужно передать в функцию структуру или объект, то передавать его целиком можно, но это может отнять кучу памяти и времени, ведь они могут быть очень большими. В простых примерах это незаметно, но в реальных программах, где это может повторяться тысячи и миллионы раз, тормоза будут огромные. Вместо этого передаете указатель или ссылку и получаете из функции доступ к объекту.
Уже говорили о динамическом выделении памяти. Если еще про это не читали, то прочитаете. Там без указателей В ПРИНЦИПЕ не обойтись.
Это лишь несколько примеров. Чем глубже будете вникать в С++, тем больше об этом узнаете.
И еще. Не думайте, что программисты до Вас были дураками.
Отслеживать
user207618
ответ дан 4 янв 2012 в 18:56
23.9k 2 2 золотых знака 37 37 серебряных знаков 69 69 бронзовых знаков
- Для возврата нескольких значений из функции. В качестве аргумента передаётся указатель на переменную, функция записывает туда значение. Такой подход очень распространён в DirectX, OpenGL, Windows API и других библиотеках в стиле C. Для этого можно использовать и ссылки, но не рекомендуется, так как синтаксис передачи и возврата неотличим.
- Для хранения адреса динамически выделенной памяти. Она отличается от обычной тем, что программист сам регулирует время жизни объектов, и её больше (а размер стека всего порядка мегабайта). Если адрес будет потерян, то память нельзя будет ни использовать, ни освободить. Возникнет утечка памяти.
- C-строка представляет собой указатель на её первый символ.
- Для создания различных структур данных: связанных списков, деревья и т. д.
- Для передачи аргумента в функцию без копирования (и вызова конструктора для объектов), которое может оказаться долгим для сложных объектов. Правда, здесь лучше использовать константные ссылки.
Таким образом, примений указателей очень много.
Отслеживать
@Xyanight, вспомните, что массивы в Си представляются указателями (даже не в случае параметров). Например: int a[10], *b = a+5; . printf («%d\n»,b[0]); // распечатает значение a[5] Вообще указатели в Си позволяют писать более обобщенный код.
4 янв 2012 в 16:46
В качестве аргумента передаётся указатель на переменную, функция записывает туда значение.
27 июл 2015 в 14:05
А зачем нужны почтовые адреса? Можно же общаться сразу с людьми. Но иногда приходится поручать доставку письма почтальону, которому надо сначала сказать, куда конкретно он должен доставить письмо, так как один и тот же почтальон должен уметь единообразно для адресанта доставлять письма всем адресатам. Как? Лезть в его днк нельзя, нельзя его даже переучивать. Указатель – это такая величина, в которой можно хранить адрес. А ссылка – это нечто, ведущее себя как указатель, но имеющее при этом синтаксис сразу целевой величины, которую мы по этому адресу ищем. То есть поле на конверте с адресом Пети, притворяющееся самим Петей. На это поле на конверте можно наорать вместо Пети, а обидится Петя. По указателю же можно только нанять хулигана, поручив ему наорать на Петю. Совсем же по-другому выглядит, а результат тот же. В одном случае мы голос посрвали, в другом – явно послали посредника. Но по указателю можно послать: почтальона, шпиона, хулигана и киллера, а по ссылке – только наорать на адрес на конверте, спокойно ему что-то сказать или поглазеть прямо на Петин стол, но киллеры даже не поймут, чего от них хотят, а сами мы убивать не умеем.
Отслеживать
ответ дан 8 ноя 2022 в 13:12
Тарас Атавин Тарас Атавин
204 1 1 серебряный знак 9 9 бронзовых знаков
Чтобы выделять большое количество памяти. Советую прочитать про стек и кучу (heap). На стеке при большом объеме данных будет происходить переполнение.
Отслеживать
ответ дан 4 янв 2012 в 14:03
221 1 1 серебряный знак 10 10 бронзовых знаков
Вот именно! Автору вопроса нужно смотреть в сторону размерных и ссылочных типов данных, как они устроены, какие отличия, где хранятся, зачем их разделили и тд. К чему тут тролинг.
4 янв 2012 в 15:56
Нeт, я пoнял пpинцип paбoты, нo нe пoнял oднoгo — ЗAЧEM Малеха противоречивый бред? Не находите?
4 янв 2012 в 16:00
Согласен — автор не разобрался в данной теме!
4 янв 2012 в 16:13
@AlexWindHope ну значит плохо объясняли
4 янв 2012 в 16:14
public и private предполагает что код может быть использовн кем-то еще, кто может залезть своими руками куда не надо и все поломать.
Указатели в C++: зачем нужны, когда использовать и чем отличаются от обращения к объекту напрямую
В какой ситуации нужно использовать указатели, а в какой сами объекты? Ниже мы постарались ответить на этот вопрос.
Даже если большинство программистов понимают, в чем разница между объектами и указателями на них, иногда бывает не совсем понятно, в пользу какого из способов обращения к объекту стоит делать выбор. Ниже мы постарались ответить на этот вопрос.
Вопрос
Я заметил, что нередко программисты, чей код я видел, используют указатели на объекты чаще, чем сами эти объекты, т.е., например, используют следующую конструкцию:
Object *myObject = new Object;
Object myObject;
Аналогично с методами. Почему вместо этого:
myObject.testFunc();
мы должны писать вот это:
myObject->testFunc();
Я так понимаю, что это дает выигрыш в скорости, т.к. мы обращаемся напрямую к памяти. Верно? P.S. Я перешел с Java.
Ответ
Заметим, кстати, что в Java указатели не используются в явном виде, т.е. программист не может в коде обратиться к объекту через указатель на него. Однако на деле в Java все типы, кроме базовых, являются ссылочными: обращение к ним происходит по ссылке, хотя явно передать параметр по ссылке нельзя. И еще, на заметку, new в C++ и в Java или C# — абсолютно разные вещи.
Для того, чтобы дать небольшое представление, что же такое указатели в C++, приведем два аналогичных фрагмента кода:
Object object1 = new Object(); // Новый объект Object object2 = new Object(); // Еще один новый объект object1 = object2;// Обе переменные ссылаются на объект, на который раньше ссылалась object2 // При изменении объекта, на который ссылается object1, изменится и // object2, потому что это один и тот же объект
Ближайший эквивалент на C++:
Object * object1 = new Object(); // Память выделена под новый объект // На эту память ссылается object1 Object * object2 = new Object(); // Аналогично со вторым объектом delete object1; // В C++ нет системы сборки мусора, поэтому если этого не cделать, // к этой памяти программа уже не сможет получить доступ, // как минимум, до перезапуска программы // Это называется утечкой памяти object1 = object2; // Как и в Java, object1 указывает туда же, куда и object2
Однако вот это – совершенно другая вещь (C++):
Object object1; // Новый объект Object object2; // Еще один object1 = object2;// Полное копирование объекта object2 в object1, // а не переопределение указателя – очень дорогая операция
На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.
На самом деле, совсем нет. Работа с указателями оформлена в виде кучи, в то время как работа с объектами – это стек, более простая и быстрая структура. Если вы новичок, то у нас для вас есть материал, в котором мы подробно рассказываем, что такое стек и куча.
Строго говоря, этот вопрос объединяет в себе два различных вопроса. Первый: когда стоит использовать динамическое распределение памяти? Второй: когда стоит использовать указатели? Естественно, здесь мы не обойдемся без общих слов о том, что всегда необходимо выбирать наиболее подходящий инструмент для работы. Почти всегда существует реализация лучше, чем с использованием ручного динамического распределения (dynamic allocation) и / или сырых указателей.
Динамическое распределение
В формулировке вопроса представлены два способа создания объекта. И основное различие заключается в сроке их жизни (storage duration) в памяти программы. Используя Object myObject; , вы полагаетесь на автоматическое определение срока жизни, и объект будет уничтожен сразу после выхода из его области видимости. А вот Object *myObject = new Object; сохраняет жизнь объекту до того момента, пока вы вручную не удалите его из памяти командой delete . Используйте последний вариант только тогда, когда это действительно необходимо. А потому всегда делайте выбор в пользу автоматического определения срока хранения объекта, если это возможно.
Обычно принудительное установления срока жизни применяется в следующих ситуациях:
- Вам необходимо, чтобы объект существовал и после выхода из области его видимости — именно этот объект, именно в этой области памяти, а не его копия. Если для вас это не принципиально (в большинстве случаев это так), положитесь на автоматическое определение срока жизни. Однако вот пример ситуации, когда вам может понадобиться обратить к объекту вне его области видимости, однако это можно сделать, не сохраняя его в явном виде: записав объект в вектор, вы можете “разорвать связь” с самим объектом — на самом деле он (а не его копия) будет доступен при вызове из вектора.
- Вам необходимо использовать много памяти, которая может переполнить стек. Здорово, если с такой проблемой не приходится сталкиваться (а с ней сталкиваются очень редко), потому что это “вне компетенции” C++, но к сожалению, иногда приходится решать и эту задачу.
- Вы, например, точно не знаете размер массива, который придется использовать. Как известно, в C++ массивы при определении имеют фиксированный размер. Это может вызвать проблемы, например, при считывании пользовательского ввода. Указатель же определяет только тот участок в памяти, куда будет записано начало массива, грубо говоря, не ограничивая его размер.
Если использование динамического распределения необходимо, то вам стоит инкапсулировать его с помощью умного указателя (что такое умный указатель можете прочитать в нашей статье) или другого типа, поддерживающего идиому “Получение ресурса есть инициализация” (стандартные контейнеры ее поддерживают — это идиома, в соответствии с которой ресурс: блок памяти, файл, сетевое соединение и т.п. — при получении инициализируется в конструкторе, а затем аккуратно уничтожается деструктором). Умными являются, например, указатели std::unique_ptr и std::shared_ptr .
Указатели
Однако есть случаи, когда использование указателей оправдано не только с точки зрения динамического распределения памяти, но почти всегда есть альтернативный путь, без использования указателей, который вам и следует выбрать. Как и ранее, скажем: всегда делайте выбор в пользу альтернативы, если нет особенной необходимости в использовании указателей.
Случаями, когда использование указателей можно рассматривать как возможный вариант, можно назвать следующие:
- Ссылочная семантика. Иногда может быть необходимо обратиться к объекту (вне зависимости от того, как под него распределена память), поскольку вы хотите обратиться в функции именно в этому объекту, а не его копии — т.е. когда вам требуется реализовать передачу по ссылке. Однако в большинстве случаев, здесь достаточно использовать именно ссылку, а не указатель, потому что именно для этого ссылки и созданы. Заметьте, что это несколько разные вещи с тем, что описано в пункте 1 выше. Но если вы можете обратиться к копии объекта, то и ссылку использовать нет необходимости (но заметьте, копирование объекта — дорогая операция).
- Полиморфизм. Вызов функций в рамках полиморфизма (динамический класс объекта) возможен с помощью ссылки или указателя. И снова, использование ссылок более предпочтительно.
- Необязательный объект. В этом случае можно использовать nullptr , чтобы указать, что объект опущен. Если это аргумент функции, то лучше сделайте реализацию с аргументами по умолчанию или перегрузкой. С другой стороны, можно использовать тип, который инкапсулирует такое поведение, например, boost::optional (измененный в C++14 std::optional ).
- Повышение скорости компиляции. Вам может быть необходимо разделить единицы компиляции (compilation units). Одним из эффективных применений указателей является предварительная декларация (т.к. для использования объекта вам необходимо предварительно его определить). Это позволит вам разнести единицы компиляции, что может положительно сказаться на ускорении времени компиляции, внушительно уменьшив время, затрачиваемое на этот процесс.
- Взаимодействие с библиотекой C или C-подобной. Здесь вам придется использовать сырые указатели, освобождение памяти из-под которых вы производите в самый последний момент. Получить сырой указатель можно из умного указателя, например, операцией get . Если библиотека использует память, которая впоследствии должна быть освобождена вручную, вы можете оформить деструктор в умном указателе.

Следите за новыми постами по любимым темам
Подпишитесь на интересующие вас теги, чтобы следить за новыми постами и быть в курсе событий.
Зачем нужны указатели в C++?
Как правило, многие программисты понимают разницу между объектами и указателями на объекты. Тем не менее не всегда ясно, в пользу какого из вышеперечисленных способов обращения делать выбор. Попробуем ответить на этот вопрос.
Однажды на StackOverflow прозвучал вопрос следующего содержания: «Why should I use a pointer rather than the object itself?» — «Почему я должен использовать указатель, а не сам объект?»
И действительно, некоторые программисты применяют указатели на объекты чаще, чем сами объекты, используя такую конструкцию:
Object *myObject=new Object;ObjectmyObject;Также и с методами, почему вместо этого:
myObject.testFunc();следует писать это:
myObject->testFunc();Разработчик, который задал вопрос, предположил, что это даёт выигрыш в скорости, ведь мы обращаемся напрямую к памяти. К слову, он перешёл в C++-программирование с Java. Что же, посмотрим, что ему ответили.
Ответ
В языке программирования Java указатели в явном виде не используются, то есть разработчик не может обратиться в коде к объекту через указатель на него. Но на деле все типы в Java, за исключением базовых, являются ссылочными, ведь обращение к ним осуществляется по ссылке, хотя явно передать по ссылке параметр нельзя. Также следует заметить, что new в C++, в Java и C# — разные вещи.
Чтобы понять, что же такое указатели в C++, рассмотрим два похожих фрагмента кода. Java:
Object object1 =newObject();// Новый объект Object object2 =newObject();// Очередной новый объект object1 = object2;// Обе переменные ссылаются на объект, на который ранее ссылалась object2 // При изменении объекта, на который ссылается object1, произойдет изменение и // object2, ведь это один и тот же объектЭквивалентный код на C++:
Object* object1 =newObject();// Память выделена под новый объект // На эту память ссылается object1 Object* object2 =newObject();// Аналогично со вторым объектом delete object1; // В C++ нет системы сборки мусора, поэтому если этого не cделать, // к этой памяти программа уже не сможет получить доступ, // как минимум до перезапуска // Это не что иное, как утечка памяти object1 = object2;// Как и в Java, object1 указывает туда же, куда и object2Но это – совсем другая вещь (C++):
Object object1;// Новый объект Object object2;// Еще один новый объект object1 = object2;// Полное копирование объекта object2 в object1, // а не переопределение указателя является очень дорогой операциейНо будет ли выигрыш в скорости, если мы будем обращаться к памяти напрямую?
Оказывается, нет. Дело в том, что работа с указателями оформлена в виде кучи, а работа с объектами представляет собой стек — более простую и быструю структуру. Таким образом, в одном вопросе мы получили два: 1. Когда лучше использовать динамическое распределение памяти? 2. Когда лучше использовать указатели?
Конечно, всегда желательно выбирать для работы наиболее подходящий инструмент. Но почти всегда существует реализация лучше, чем с применением ручного динамического распределения (dynamicallocation) и/или «сырых» указателей.
Динамическое распределение
Формулировка вопроса подразумевает 2 способа создания объекта. Главное различие — срок их жизни (storageduration) в памяти программы.
Применяя ObjectmyObject; , разработчик полагается на автоопределение срока жизни, то есть объект уничтожится сразу же после выхода из его области видимости. При этом Object *myObject = newObject; сохраняет жизнь объекту до того самого момента, пока разработчик вручную не удалит его из памяти с помощью команды delete. Применяйте последний вариант лишь тогда, когда это на самом деле надо. А значит, всегда выбирайте автоматическое определение срока хранения объекта, если, конечно, это возможно.
Что касается принудительного установления срока жизни, то оно используется в следующих случаях: • надо, чтобы объект существовал и после выхода из области его видимости. Мы говорим об именно этом объекте и именно в этой области памяти, а не про его копию. Если же для вас это не является принципиальным (а чаще всего это так), следует положиться на автоопределение срока жизни; • надо применять много памяти, которая может переполнить стек. В принципе, с этой проблемой сталкиваются редко, но, бывает, приходится решать и такую задачу; • точно не известен размер массива, который придётся использовать. Вы должны знать, что в C++ массивы имеют фиксированный размер при определении. Это иногда вызывает проблемы, к примеру, во время считывания пользовательского ввода. Указатель же определяет лишь тот участок в памяти, куда записывается начало массива.
Когда применение динамического распределения необходимо, стоит инкапсулировать его посредством умного указателя (о таких указателях мы уже писали) или иного типа, поддерживающего концепцию “Получение ресурса есть инициализация”. Умными указателями, например, являются std::unique_ptr и std::shared_ptr .
Указатели
Иногда применение указателей оправдано не только из-за динамического распределения памяти. Однако помните, что практически всегда существует альтернативный путь, не предполагающий использование указателей — его и следует выбрать. То есть, если особая необходимость использовать указатели отсутствует, всегда выбирайте альтернативу.
Однако рассмотрим случаи, когда применение указателей оправдано: • ссылочная семантика. Иногда нужно обратиться к объекту вне зависимости от того, каким образом под него распределена память, если вы желаете обратиться в функции именно к этому объекту, а не к его копии. То есть речь идёт о случае, когда надо реализовать передачу по ссылке. Но, опять же, чаще всего тут достаточно использовать не указатель, а именно ссылку, ведь как раз для этого и созданы ссылки. Но если есть возможность обратиться к копии объекта, то и ссылку, соответственно, использовать нет необходимости (однако учтите, что копирование объекта является дорогой операцией); • полиморфизм. С помощью ссылки либо указателя возможен вызов функций в рамках полиморфизма. Но и тут использование ссылок предпочтительнее; • необязательный объект. Тут можно применять nullptr, дабы указать, что объект опущен. Но если это аргумент функции, сделайте реализацию с аргументами по умолчанию либо перегрузкой. С другой стороны, вы можете использовать тип, инкапсулирующий такое поведение, допустим, boost::optional (измененный в C++14 std::optional); • повышение скорости компиляции. Иногда нужно разделить единицы компиляции (compilationunits). Один из эффективных вариантов использования указателей — предварительная декларация. В результате вы получите возможность разнести единицы компиляции, что обычно положительно сказывается на ускорении времени компиляции. • взаимодействие с С-подобной библиотекой. Здесь придётся задействовать сырые указатели, освобождение памяти из-под которых вы выполняете в самый последний момент. Сырой указатель можно получить из умного, используя операцию get. Если библиотека использует память, которая потом должна освобождаться вручную, можно оформить в умном указателе деструктор.
Указатели
Указатели представляют собой объекты, значением которых служат адреса других объектов (переменных, констант, указателей) или функций. Как и ссылки, указатели применяются для косвенного доступа к объекту. Однако в отличие от ссылок указатели обладают большими возможностями.
Определение указателя
Для определения указателя надо указать тип объекта, на который указывает указатель, и символ звездочки *:
тип_данных* название_указателя;Сначала идет тип данных, на который указывает указатель, и символ звездочки *. Затем имя указателя.
Например, определим указатель на объект типа int:
int* p;Такой указатель может хранить только адрес переменной типа int , но пока данный указатель не ссылается ни на какой объект и хранит случайное значение. Мы его даже можем попробовать вывести на консоль:
#include int main()
Например, в моем случае консоль вывела "0x8" - некоторый адрес в шестнадцатеричном формате (обычно для представления адресов в памяти применяется шестнадцатеричная форма). Но также можно инициализировать указатель некоторым значением:
int* p<>;Поскольку конкрентное значение не указано, указатель в качестве значения получает число 0. Это значение представляет специальный адрес, который не указывает не на что. Также можно явным образом инициализировать нулем, например, используя специальную константу nullptr :
int* p;Хотя никто не запрещает не инициализировать указатели. Однако в общем случае рекомендуется все таки инициализировать, либо каким-то конкретным значением, либо нулем, как выше. Так, к примеру, нулевое значение в будущем позволит определить, что указатель не указывает ни на какой объект.
Cтоит отметить что положение звездочки не влияет на определение указателя: ее можно помещать ближе к типу данных, либо к имени переменной - оба определения будут равноценны:
int* p1<>; int *p2<>;Также стоит отметить, что размер значения указателя (хранимый адрес) не зависит от типа указателя. Он зависит от конкретной платформы. На 32-разрядных платформах размер адресов равен 4 байтам, а на 64-разрядных - 8 байтам. Например:
#include int main() < int *pint<>; double *pdouble<>; std::cout
В данном случае определены два указателя на разные типы - int и double. Переменные этих типов имеют разные размеры - 4 и 8 байт соответственно. Но размеры значений указателей будут одинаковы. В моем случае на 64-разрядной платформе размер обоих указателей равен 8 байтам.
Получение адреса и оператор &
С помощью операция & можно получить адрес некоторого объекта, например, адрес переменной. Затем этот адрес можно присвоить указателю::
int number ; int *pnumber ; // указатель pnumber хранит адрес переменной numberВыражение &number возвращает адрес переменной number . Поэтому переменная pnumber будет хранить адрес переменной number . Что важно, переменная number имеет тип int, и указатель, который указывает на ее адрес, тоже имеет тип int. То есть должно быть соответствие по типу. Однако также можно использовать ключевое слово auto :
int number ; auto *pnumber ; // указатель pnumber хранит адрес переменной numberЕсли мы попробуем вывести адрес переменной на консоль, то увидим, что он представляет шестнадцатиричное значение:
#include int main() < int number ; int *pnumber ; // указатель pnumber хранит адрес переменной number std::cout
Консольный вывод программы в моем случае:
number addr: 0x1543bffc74В каждом отдельном случае адрес может отличаться и при разных запусках программы может меняться. К примеру, в моем случае машинный адрес переменной number - 0x1543bffc74 . То есть в памяти компьютера есть адрес 0x1543bffc74, по которому располагается переменная number. Так как переменная x представляет тип int , то на большинстве архитектур она будет занимать следующие 4 байта (на конкретных архитектурах размер памяти для типа int может отличаться). Таким образом, переменная типа int последовательно займет ячейки памяти с адресами 0x1543bffc74, 0x1543bffc75, 0x1543bffc76, 0x1543bffc77.
И указатель pnumber будет ссылаться на адрес, по которому располагается переменная number, то есть на адрес 0x1543bffc74.
Итак, указатель pnumber хранит адрес переменной number, а где хранится сам указатель pnumber? Чтобы узнать это, мы также можем применить к переменной pnumber операцию &:
#include int main() < int number ; int *pnumber ; // указатель pnumber хранит адрес переменной number std::cout
Консольный вывод программы в моем случае:
number addr: 0xe1f99ff7cc pnumber addr: 0xe1f99ff7c0Здесь мы видим, что переменная number располагается по адресу 0xe1f99ff7cc , а указатель, который хранит этот адрес, - по адресу 0xe1f99ff7c0 . Из вывода видно, что обе переменные хранятся совсем рядом в памяти
Получение значения по адресу
Но так как указатель хранит адрес, то мы можем по этому адресу получить хранящееся там значение, то есть значение переменной number. Для этого применяется операция * или операция разыменования ("indirection operator" / "dereference operator"). Результатом этой операции всегда является объект, на который указывает указатель. Применим данную операцию и получим значение переменной number:
#include int main() < int number ; int *pnumber ; std::cout Address = 0x44305ffd4c Value = 25Значение, которое получено в результате операции разыменования, можно присвоить другой переменной:
int n1 ; int *pn1 ; // указатель pn1 хранит адрес переменной n1 int n2 < *pn1>; // n2 получает значение, которое хранится по адресу в pn1 std::cout int x = 10; int *px = &x; *px = 45; std::cout
