Указатели и ссылки

 

Поскольку, переменная – это поименованная область памяти, то естественно, что язык С предоставляет возможность работы с адресами памяти напрямую. Для этих целей используются указатели. Указатели похожи на обоюдоострое оружие: их возможности огромны, однако обезвредить ошибки в них особенно трудно.

Указатель это переменная, содержащая в качестве значения адрес какой-либо области оперативной памяти.

Наглядно указатель можно представить следующим образом (рис. 14).

Значение по указателю

Рис. 14. Визуальное представление указателя

 

При этом указатель содержит не само «Значение по указателю», а адрес области памяти, где располагается «Значение по указателю». Чтобы получить «Значение по указателю» необходимо к имени указателя применить оператор снятия адреса (*).

Оператор объявления указателя выглядит следующим образом:

тип указателя V *имя указателя;

Область памяти, на которую ссылается указатель, может быть выделена непосредственно под этот указатель, либо может быть использована другой переменной или константой. Размер указываемой памяти определяется типом указателя, который всегда должен совпадать с типом переменной, если указатель используется для хранения ее адреса.

Существует три способа инициализации указателя. Рассмотрим подробнее каждый из них.

Ниже приводится пример инициализации (объявления с присвоением начального значения) указателя адресом динамической памяти (с помощью оператора new) и присвоения значения по хранящемуся в переменной-указателе адресу (рис. 15).

int *ip=new int; // инициализация указателя ip

адресом динамической памяти

*ip=5; //присвоение значения по указателю

ip
5

Рис. 15. Визуальное представление указателя,
инициализированного адресом динамической памяти

 

Другой способ инициализации указателя – инициализация адресом существующей переменной того же типа с помощью унарной операции & (рис. 16).

int *ip1,i=10; // объявление указателя ip1 и переменной

того же типа

ip=&i; // инициализация указателя адресом

другой переменной того же типа

10
ip1
i

Рис. 16. Визуальное представление указателя,
инициализированного адресом существующей переменной того же типа

 

Второй вариант инициализации указателя возможен, но не желателен, так как к области памяти, где хранится значение 10, можно обратиться двумя разными способами – при помощи указателя и просто по имени переменной i.

Третий способ инициализации указателя используется в случае работы с несколькими переменными-указателями и подразумевает возможность инициализации объявленного указателя с помощью другого указателя, уже правильно инициализированного.

Важно! Нельзя использовать объявленный, но неинициализированный указатель, такой указатель называют «диким». Ничто не может доставить больше неприятностей, чем «дикий» указатель! Ошибочный указатель трудно найти, потому что ошибка в самом указателе никак себя не проявляет. Проблемы возникают при попытке обратиться к объекту с помощью этого указателя. Если значение указателя неправильное, то программа с его помощью обращается к произвольной ячейке памяти. При чтении в программу попадают неправильные данные, а при записи искажаются другие данные, хранящиеся в памяти, или портится участок программы, не имеющий никакого отношения к ошибочному указателю. В обоих случаях ошибка может не проявиться вовсе или проявиться позже в форме, никак не указывающей на ее причину. Поскольку ошибки, связанные с указателями, особенно трудно выявить, при работе с указателями следует соблюдать особую осторожность. В M S VS 2008 при работе с проектом отладчик сообщит об ошибке использования переменной, не имеющей значения, но это только при запуске программы из оболочки. Если же запускать независимый исполняемый файл, то сообщение о такой ошибке не возникает и может привести к вышеуказанным ситуациям, что недопустимо.

Возможно, сложности восприятия указателей начинающим программистом провоцируются минимумом синтаксиса работы с указателем. Для работы с указателями используются всего два знака операций: * и &. Знак * – это, так называемая, операция снятия адреса (операция разадресации), которая применяется к указателю, чтобы получить значение, хранящееся по соответствующему адресу. Также этот знак используется в строке объявления указателя перед его именем (или точнее после типа переменной), показывая тем самым, что объявленная переменная – не обычная переменная, а переменная-указатель, так как тип переменной с добавлением символа * читается как указатель на этот тип. Знак & – операция взятия адреса применяется к любой переменной, константе или указателю для того чтобы получить ее адрес. При применении & к имени переменной получается ссылка.

Ссылка – это константный указатель на существующую переменную, значение ссылки инициализируется адресом этой переменной и не может быть изменено.

Применение указателей очень полезно при:

- работе с массивами;

- получении из функции больше одного результата;

- работе с потоками;

- управлении памятью.

Важно! Указателю можно присваивать только значение адреса. Если в операторе присваивания слева от знака = стоит указатель, то справа должен стоять адрес переменной или другой указатель, но обязательного того же типа.

 

Контрольные вопросы и задания

1) Что такое переменная? Какие имена можно задавать переменным?

2) Каким образом осуществляется объявление переменных?

3) Что такое инициализация? Какими способами можно инициализировать переменные?

4) Приведите классификацию известных Вам типов данных.

5) Что такое именованная константа? Каким образом в языке С можно создавать константы?

6) Какие переменные называются булевскими, для каких целей их можно применять?

7) Что такое enumeration? Приведите пример конструкции, использующий enumeration.

8) Что такое указатель? Приведите пример объявления и инициализации указателя.

9) Для каких задач можно использовать указатель?

10) Дайте определение ссылке.

11) Объявлены следующие переменные и указатели:

int *ipa=new int, ia=-2;

Найдите допустимые из перечисленных ниже операторы и объясните, почему неправильны остальные.

ipa=ia; ipa=*ia; ipa=&ia; *ipa=ia; *ipa=*ia; *ipa=&ia; &ipa=ia; &ipa=*ia; &ipa=&ia;

 

ГЛАВА 4