- •О.Л. Викентьева, А.Н. Гусин, O.A. Полякова
- •ПРОЕКТИРОВАНИЕ ПРОГРАММ И ПРОГРАММИРОВАНИЕ НА C++
- •1. СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ
- •10.1. Базовые конструкции структурного программирования
- •10.3. Составные операторы
- •10.4. Операторы выбора
- •10.5. Операторы циклов
- •10.6. Операторы перехода
- •11. ПРИМЕРЫ РЕШЕНИЯ ЗАДАЧ С ИСПОЛЬЗОВАНИЕМ ОСНОВНЫХ ОПЕРАТОРОВ C++
- •11.2. Программирование арифметических циклов
- •11.3. Программирование итерационных циклов
- •11.4. Программирование вложенных циклов
- •12. МАССИВЫ
- •12.1. Определение массива в C/C++
- •12.2. Примеры решения задач с использованием массивов
- •13. УКАЗАТЕЛИ
- •13.1. Понятие указателя
- •13.2. Динамическая память
- •13.3. Операции с указателями
- •14. ССЫЛКИ
- •15.3. Динамические массивы
- •СИМВОЛЬНАЯ ИНФОРМАЦИЯ И СТРОКИ
- •16.1. Представление символьной информации
- •16.2. Библиотечные функции для работы со строками
- •16.3. Примеры решения задач с использованием строк
- •17. ФУНКЦИИ В C++
- •17.1. Объявление и определение функций
- •17.2. Прототип функции
- •17.3. Параметры функции
- •17.4. Локальные и глобальные переменные
- •17.5. Функции и массивы
- •17.5.1. Передача одномерных массивов как параметров функции
- •17.5.2. Передача строк в качестве параметров функций
- •17.5.3. Передача многомерных массивов в функцию
- •17.6. Функции с начальными значениями параметров (по умолчанию)
- •17.7. Подставляемые (inline) функции
- •17.8. Функции с переменным числом параметров
- •17.9. Рекурсия
- •17.11. Шаблоны функций
- •17.12. Указатель на функцию
- •17.13. Ссылки на функцию
- •18. ТИПЫ ДАННЫХ, ОПРЕДЕЛЯЕМЫЕ ПОЛЬЗОВАТЕЛЕМ
- •18.1. Переименование типов
- •18.2. Перечисления
- •18.3. Структуры
- •18.3.1. Работа со структурами
- •18.3.2. Битовые поля
- •18.3.3. Объединения
- •19. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ
- •19.1. Создание элемента списка
- •19.2. Создание списка из п элементов
- •19.3. Перебор элементов списка
- •19.4. Удаление элемента с заданным номером
- •19.5. Добавление элемента с заданным номером
- •19.6. Двунаправленные списки
- •19.7. Очереди и стеки
- •19.8. Бинарные деревья
- •19.9. Обход дерева
- •19.10. Формирование дерева
- •19.11. Удаление элемента из дерева
- •19.12. Обработка деревьев с помощью рекурсивного обхода
- •20. ПРЕПРОЦЕССОРНЫЕ СРЕДСТВА
- •20.1. Стадии и команды препроцессорной обработки
- •20.2. Директива #define
- •20.3. Включение текстов из файлов
- •20.4. Условная компиляция
- •20.5. Макроподстановки средствами препроцессора
- •21.1. Проектирование программы
- •21.2. Кодирование и документирование программы
- •СПИСОК ЛИТЕРАТУРЫ
- •ПРОЕКТИРОВАНИЕ ПРОГРАММ И ПРОГРАММИРОВАНИЕ НА C++
13.УКАЗАТЕЛИ
13.1.Понятие указателя
Указатели являются специальными объектами в программах на C/C++. Указатели предназначены для хранения адресов памяти.
Когда компилятор обрабатывает оператор определения перемен ной, например int i=10;, то в памяти выделяется участок памяти в соответствии с типом переменной (для int размер участка памяти составит 4 байта) и записывается в этот участок указанное значение. Все обращения к этой переменной компилятор заменит адресом об ласти памяти, в которой хранится эта переменная (рис. 9).
10 int a— 10
Рис. 9. Значение переменной и ее адрес
Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями. Указатель не является самостоятельным типом, он все гда связан с каким-то другим типом.
Указатели делятся на две категории: указатели на объекты и ука затели на функции. Рассмотрим указатели на объекты, которые хра нят адрес области памяти, содержащей данные определенного типа.
В простейшем случае объявление указателя имеет вид
тип* имя;
Знак * обозначает указатель и относится к типу переменной, по этому его рекомендуется ставить рядом с типом, а от имени перемен ной отделять пробелом, за исключением тех случаев, когда описыва ются несколько указателей. При описании нескольких указателей знак * ставится перед именем переменной-указателя, так как иначе будет непонятно, что эта переменная также является указателем,
int* i;
double *f, *ff;//flBa указателя char* c;
Тип NK чет быть любым, кроме ссылки.
Размер указателя зависит от модели памяти. Можно определить
указатель на указатель i n t * * а ;
Указатель может быть константой или переменной, а также ука
зывать на константу или переменную. |
|
|
|
|
||||
i n t i ; |
|
//ц е л а я |
п ерем ен ная |
|
||||
c o n s t |
i n t c i = l ; //ц е л а я к о н ст а н т а |
|
||||||
i n t * |
p i ; |
|
//у к а з а т е л ь |
на |
целую |
переменную |
||
c o n s t |
i n t * |
p c i ; //у к а з а т е л ь |
на |
целую |
к о н ста н ту |
|||
Указатель можно сразу проинициализировать: |
|
|||||||
//у к а з а т е л ь |
на |
целую |
переменную |
|
||||
i n t * |
p i= & i; |
|
|
|
|
|
|
|
//у к а з а т е л ь |
на |
целую |
к о н ста н ту |
|
||||
c o n s t i n t * p c i= & c i; |
|
|
|
|
|
|||
//у к а з а т е л ь - к о н с т а н т а |
на |
переменную |
целого типа |
|||||
i n t * c o n s t c p i= & i; |
|
|
|
|
|
|||
//у к а з а т е л ь - к о н с т а н т а |
на |
целую к о н ст а н т у |
||||||
c o n s t |
i n t * |
c o n s t cp c= & ci; |
|
|
|
Если модификатор c o n s t относится к указателю (т.е. находится
между именем указателя и *), то он запрещает изменение указателя, а если он находится слева от типа (т.е. слева от *), то он запрещает изменение значения, на которое указывает указатель.
Для инициализации указателя существуют следующие способы:
• |
с помощью операции получения адреса |
||
i n t а = 5 ; |
|
||
i n t * |
р=&а; или i n t |
р (& а ); |
|
• |
с помощью проинициализированного указателя |
||
in t * |
г= р; |
|
|
• |
адрес присваивается в явном виде |
||
c h a r* |
c p = (c h a r* )0 x |
В800 0000; |
|
где Ox |
В800 0000 - шестнадцатеричная константа; (c h a r* ) - |
||
операция приведения типа. |
|
||
• |
присваивание пустого значения: |
||
i n t * |
N=NULL; |
|
|
i n t * |
R=0; |
|
13.2. Динамическая память
Все переменные, объявленные в программе, размещаются в од ной непрерывной области памяти, которую называют сегментом дан ных (64 Кб). Такие переменные не меняют своего размера в ходе вы полнения программы и называются статическими. Размера сегмента данных может быть недостаточно для размещения больших массивов информации. Выходом из этой ситуации-является использование ди намической памяти. Динамическая память - это память, выделяемая программе для ее работы за вычетом сегмента данных, стека, в кото ром размещаются локальные переменные подпрограмм и собственно тела программы.
Для работы с динамической памятью используют указатели. С их помощью осуществляется доступ к участкам динамической па мяти, которые называются динамическими переменными. Динамиче ские переменные создаются с помощью специальных функций и операций. Они существуют либо до конца работы программ, либо до тех пор, пока не будут уничтожены с помощью специальных функций или операций.
Для создания динамических переменных используют операцию new, определенную в C++:
указатель = new имя_типа[инициализатор];
где инициализатор - выражение в круглых скобках.
Операция new позволяет выделить и сделать доступным участок динамической памяти, который соответствует заданному типу дан ных. Если задан инициализатор, то в этот участок будет занесено значение, указанное в инициализаторе.
int* x=new int(5);
Для удаления динамических переменных используется операция delete, определенная в C++:
delete указатель;
где указатель содержит адрес участка памяти, ранее выделенный с помощью операции new.
delete х;
13.3.Операции с указателями
Суказателями можно выполнять следующие операции: - разыменование (*); - присваивание;
-арифметические операции (сложение с константой, вычита ние, инкремент ++, декремент — );
-сравнение;
-приведение типов.
Операция разыменования предназначена для получения значе ния переменной или константы, адрес которой хранится в указателе. Если указатель указывает на переменную, то это значение можно изменять, также используя операцию разыменования.
i n t а ;//п е р е м е н н а я |
ти па i n t |
||
i n t * |
pa=new |
i n t ; / /у к а з а т е л ь и вы деление |
|
//п а м я т и |
под динам ическую переменную |
||
* р а = 1 0 ;//п р и с в о и л и |
зн ач ен и е дин ам ической |
||
//п е р е м е н н о й , |
на которую у к а зы в а е т у к а з а т е л ь |
||
а = * р а ;//п р и с в о и л и |
зн ач ен и е перем енной а |
Присваивать значение указателям-константам запрещено. Приведение типов. На одну и ту же область памяти могут ссы
латься указатели разного типа. Если применить к ним операцию ра зыменования, то получатся разные результаты,
i n t а= 1 2 3 ;
i n t * |
pi= & a; |
c h a r* |
р с = ( c h a r * ) &а; |
f l o a t * p f = ( f l o a t * ) & a ;
p r i n t f ( " \n % x \t% i" , p i , * p i ); p r i n t f ( " \ n % x \ t % c " ,p c ,* p c ) ; p r i n t f ( " \ n % x \ t % f " , p f , * p f ) ;
При выполнении этой программы получатся следующие результаты:
6 6 fd 9 c |
123 |
6 6 fd 9 c |
{ |
6 6 fd 9 c |
0 .0 0 0 0 0 0 |
Таким образом, адрес у трех указателей один и тот же, но при разыменовании получаются разные значения в зависимости от типа указателя.
В примере при инициализации указателя была использована опе рация приведения типов. При использовании в выражении указателей разных типов явное преобразование требуется для всех типов, кроме v o id * . Указатель может неявно преобразовываться в значения типа b o o l, при этом ненулевой указатель преобразуется в t r u e , а нуле вой в f a l s e .
Арифметические операции применимы только к указателям од
ного типа.
• Инкремент увеличивает значение указателя на величину
sizeof(тип). char* рс; int* pi; double* pd;
pc++; |
//значение увеличится на 1 |
|
pi++; |
//значение увеличится на |
4 |
pd++; |
//значение увеличится на |
8 |
•Декремент уменьшает значение указателя на величину sizeof(тип).
•Разность двух указателей - это разность их значений, делен ная на размер типа в байтах.
int а=123/ Ь=456, с=789;
int* pil=&a;
int* pi2=&b; int* pi3=&c;
printf("\n%x",pi1-pi2); printf (,f\n%x,f,pil-pi3) ;
Результат выполнения программы:
1
2
Суммирование двух указателей не допускается.
• Можно суммировать указатель и константу: pi3=pi3+2;
pi2=pi2+l;
p r i n t f ( "\ n % x \t % d ,f, p i l , * p i l ) ;
p r i n t f ( " \ n % x \ t % d " , p i 2 , * p i 2 ) ; p r i n t f ( ,,\n % x \t % d ,f, p i 3 / * p i 3 ) ;
Результат выполнения программы:
66fd9c 123
66fd9c 123
66fd9c 123