Это особенность языка C, которая часто сбивает с толку новичков, но кажется магией, как только становится понятной: вы можете иметь множество указателей, указывающих на один и тот же адрес памяти.
Рассмотрим такой сценарий. Вы объявляете целочисленную переменную i. Затем объявляете три указателя p, q и r. Вы присваиваете им все адрес переменной i.
Посмотрите на последнюю строку. r не обязан знать о i напрямую. Он просто указывает туда, куда указывает p. А p указывает на i. Следовательно, r также указывает на i.
Оператор присваивания здесь копирует адрес, а не значение. Когда вы выполняете r = p, вы не копируете целое число, содержащееся в i. Вы копируете адрес памяти, который хранится в p.
После выполнения этого кода у i по сути появляется четыре имени. Вы можете обращаться к ней через i. Вы можете обращаться к ней через *p. Вы можете обращаться к ней через *q. Или вы можете обращаться к ней через *r.
Технических ограничений на количество указателей, которые можно таким образом «накопить», нет.
Почему это важно
Это не просто академический синтаксис. Это меняет ваше представление о потоке данных.
В языках со строгими объектными ссылками копирование объекта часто создает новый экземпляр в памяти. В C копирование указателя дешево. Это просто адрес памяти. Быстро. Маленько.
Это позволяет различным частям вашего кода манипулировать одними и теми же данными без дублирования. Измените *p, и *q сразу увидит это изменение.
Вы создаете псевдонимы для памяти.
Риск возникновения псевдонимов
Здесь «крутая особенность» превращается в недостаток.
Если p, q и r все указывают на i, любой из них может изменить i.
Теперь i равно 10. *q равно 10. *r равно 10.
Но что, если вы забудете, что r также следит за i? Вы можете предположить, что i стабильна, потому что вы не трогали её напрямую. Вы тронули только *q.
Это общий ресурс. А общие ресурсы — это место, где живут состояния гонки (race conditions) и неожиданные перезаписи данных.
Как предотвратить непреднамеренные побочные эффекты
Если вы хотите убедиться, что один указатель случайно не перезапишет данные, предназначенные для другого, используйте const.
Теперь r может читать i. Он может указывать на неё. Но он не может её изменять.
Таким образом вы устанавливаете границы в языке, который доверяет вам управление памятью вручную.
Где это применяется в системном программировании
Этот шаблон повсюду в системном коде.
Структуры ядра часто имеют несколько указателей на один и тот же блок управления. Драйверы устройств отображают одни и те же аппаратные регистры на разные логические имена.
Понимание того, что указатели — это просто метки для адресов, помогает вам отлаживать эти проблемы. Когда память повреждается, отслеживайте указатели. Кто еще





















