|
Программирование >> Процедурные приложения
Глава 9. Указатели Указатели как особый тип переменных o Объявление указателей o Использование указателей o Инициализация указателей o Ограничения на использование оператора & o Указатели на массивы o o Указатели на указатели o o o o o o o Указатели на строки Арифметические операции над указателями Применение арифметики указателей при работе с массивами Распространенная ошибка при использовании операторов ++ и -Применение квалификатора const совместно с указателями o Другие операции над указателями o Физическая реализация указателей Указатели на функции Динамическая память o Указатели типа void Подробнее об указателях и массивах o Строки (массивы типа char ) o Массивы указателей o Дополнительные сведения об указателях на указатели o Массивы строковых указателей Ссылки в языке C++ o Функции, возвращающие адреса Если вы еще не имеете четкого представления о работе указателей, то самое время подробнее познакомиться с ними. Суть концепции указателей состоит в том, что вы работаете с адресом ячейки памяти, получая лишь косвенный доступ к ее содержимому, благодаря чему появляется возможность динамически создавать и уничтожать переменные. Хотя с помощью указателей можно создавать чрезвычайно эффективные алгоритмы, сложность программы, в которой используются указатели, значительно возрастает. В языках C/C++ вопросы, связанные с указателями, массивами и строками, тесно связаны друг с другом. Поэтому данную главу можно рассматривать как непосредственное продолжение предыдущей главы. Для начинающего программиста глава может показаться чересчур сложной, но лишь в полной мере изучив тему указателей, можно начать создавать действительно профессиональные приложения. Указатели как особый тип переменных Начинающие программисты, как правило, работают только с обычными переменными. Для таких переменных память выделяется автоматически при запуске программы или функции, в которой они объявлены, и удаляется также автоматически при завершении программы или функции. Доступ к ним организуется достаточно просто - по имени: imemorycell contents+= 10; Другой способ получения доступа к значению переменной заключается в использовании другой переменной, которая содержит ее адрес. Предположим, имеется переменная типа intс именем imemorycell contents и переменная pimemory cell address, являющаяся указателем на нее. Как вы уже знаете, в C/C++ есть оператор взятия адреса &, который возвращает адрес своего операнда. Поэтому вам будет нетрудно разобраться в синтаксисе присвоения одной переменной адреса другой переменной: pimemorycell address = &imemorycell contents; Переменные, которые хранят адреса других переменных, называются указателями. На рис. 9.1 схематично показана взаимосвязь между переменной и указателем на нее. Переменная imemorycell contents представлена в памяти компьютера ячейкой с адресом 7751. После выполнения показанной выше строки программы адрес этой переменной будет присвоен указателю pimemorycell address. im е mo Г у С е 11 с О nt е nts р im е m ory addr е s s Рис. 9.1. Взаимосвязь межжду переменной и её указателями Обращение к переменной, чей адрес хранится в другой переменной, осуществляется путем помещения перед указателем оператора *: *pimemorycell address. Такая запись означает, что будет произведен косвенный доступ к ячейке памяти через имя указателя, содержащего адрес ячейки. Например, если выполнить две показанные ниже строки, то переменная imemorycell contentsпримет значение 20: pimemorycell address = &imemorycell contents; *pimemorycell address = 20; : С учетом того, что указатель pimemorycell address хранит адрес переменной imemorycell contents, обе следующие строки приведут к одному и тому же результату: присвоению переменной imemorycell contents значения 20. imemorycell contents = 20; *pimemorycell address = 20; Объявление указателей В языках C/C++ все переменные должны быть предварительно объявлены. Объявление указателя pimemorycell address выглядит следующим образом: int *pimemorycell address; Символ * говорит о том, что создается указатель. Этот указатель будет адресовать переменную типа int. Следует подчеркнуть, что в C/C++ указатели могут хранить адреса только переменных конкретного типа. Если делается попытка присвоить указателю одного типа адрес переменной другого типа, возникнет ошибка либо во время компиляции, либо во время выполнения программы. Рассмотрим пример: int *pi float real value = 98.2 6; pi = &real value; В данном случае переменная pi объявлена как указатель типа int. Но в третьей строке делается попытка присвоить этому указателю адрес переменной real value, имеющей тип float. В результате компилятор выдаст предупреждение вида несовместимые операнды в операции присваивания , а программа, использующая указатель pi, будет работать неправильно. Использование указателей В следующем фрагменте программы посредством указателей производится обмен значений между переменными iresult a и iresult b: int iresialt a = 15, iresult b = 37, itemporary; int *piresult; piresult = &iresult a; itemporary = *piresult; *piresult = iresult b; iresult b = itemporary; Первая строка содержит традиционные объявления переменных. При этом в памяти компьютера резервируются три ячейки для хранения целочисленных значений, каждой ячейке присваивается имя, и две из них инициализируются начальными значениями. Предположим, что переменная iresult a хранит свои значения в ячейке с адресом 5328, переменная iresult b связана с ячейкой 7916, a itemporary- с ячейкой 2385 (рис. 9.2). Рис. 9.2. Резервирование и инициализация ячеек памяти Во второй строке программы создается указатель piresult. При этом также происходит резервирование именованной ячейки памяти (скажем, с адресом 1920). Поскольку инициализация не производится, то в данный момент указатель содержит пустое значение. Если попытаться применить к нему оператор *, то компилятор не сообщит об ошибке, но и не возвратит никакого адреса. В третьей строке происходит присваивание указателю piresult адреса переменной iresult a(рис. 9.3). В следующей строке в переменную itemporary записывается содержимое переменной iresult a, извлекаемое с помощью выражения *piresult: itemporary = *piresult; iresult a iresult b ietemporary piresult Рис. 9.3. Присваивание указателю piresult адреса переменной iresult a
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |