Указатели
Виды оперативной памяти
Статическая память
Статическая память
Автоматическая память
Динамическая память
Динамические переменные
Адреса оперативной памяти
Ячейки памяти
Адреса динамических переменных
Указатели
Объявление указателей на переменные и константы
Указатели-константы
Обращение к указанным переменным и константам
Инициализация указателей на переменные и константы
Замечания об инициализации
Важность инициализации
Динамические переменные
Создание динамических переменных
Удаление динамических переменных
Сборка мусора
Пример программы
Указатели void
Указатели void
Операции с указателями
Операции с указателями
Операции с указателями
Указатели и массивы
Указатели и массивы
Указатели и массивы
Динамические массивы
Создание динамического массива
Освобождение памяти
Двумерные массивы
Пример определения двумерного массива
Двумерные массивы
Двумерный массив
Динамические двумерные массивы
Динамические двумерные массивы
Зубчатые массивы
Конец лекции
Структура физической памяти
Сегменты оперативной памяти
Сегменты и виды памяти
Виды указателей
Указатели и строки
3.16M
Category: informaticsinformatics

Указатели. Лекция 5. Виды оперативной памяти

1. Указатели

Лекция 5

2. Виды оперативной памяти

Современные языки программирования
работают с тремя видами памяти:
• статической,
• автоматической,
• динамической

3. Статическая память

В статической памяти располагаются:
• переменные, определения которых расположены
вне каких-либо функций или блоков (глобальные
переменные);
• переменные, определенные внутри функций или
блоков с использованием спецификатора static
(локальные статические переменные);
• коды функций

4. Статическая память

Программные объекты (переменные и
функции), размещенные в статической памяти,
существуют с момента начала выполнения
программы и до ее завершения

5. Автоматическая память

В автоматической памяти располагаются:
• переменные, определения которых расположены
внутри каких-либо функций или блоков (локальные
переменные);
• фактические параметры функций, передаваемые им
при вызове
Переменные, размещенные в автоматической
памяти, существуют до момента завершения
выполнения функции после чего
автоматическая память очищается

6. Динамическая память

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

7. Динамические переменные

создаются в
процессе выполнения программы
выполнением унарной операции new и
существуют до их удаления унарной операцией
delete
Особенности динамических переменных:
• эти переменные не имеют имен;
• это неинициализированные переменные, поэтому
перед использованием они должны быть
инициализированы

8. Адреса оперативной памяти

Оперативная память представляет собой
пронумерованную последовательность байт
Номер байта памяти называется его адресом
Адрес – это целое число, которое принято
представлять в шестнадцатеричной системе
счисления
Диапазон адресов занимает интервал от 0 до
некоторого максимального значения,
определяемого архитектурой компьютера и
операционной системой

9. Ячейки памяти

В дальнейшем будем полагать максимальное
значение адреса равным 232 -1
Для каждого типа данных стандартом языка С+
+ определяется минимально возможное
количество байт, отводимое для хранения
значений этого типа
Такая область памяти называется ячейкой
памяти
Адрес ячейки памяти совпадает с адресом ее
первого (младшего) байта

10. Адреса динамических переменных

Доступ к динамическим переменным возможен
только путем непосредственного указания их
адреса в оперативной памяти
Адрес динамической переменной является
результатом выполнения операции new
Для хранения адресов используются
переменные, называемые указателями

11. Указатели

Таким образом,
указатели – это
переменные,
хранящие адреса
других
программных
объектов
указатель q
002EFE8
0
002EFE8
0
указатель p
5
переменная X с
адресом 002EFE80

12. Объявление указателей на переменные и константы

Синтаксис объявления указателя на
переменную:
<тип переменной> *<имя указателя>;
Указатели на константы объявляются со
спецификатором const
Например:
float *x, *b; const int *c;
Здесь объявлены два указателя x и b на
переменные вещественного типа а также
указатель c на целую константу

13. Указатели-константы

Кроме того, константами могут быть сами
указатели, т.е. содержать адреса, не
меняющиеся в течение всего времени их
существования
Это свойство указателей устанавливается
квалификатором const, записанным после
символа ‘*’ в объявлении указателя, например:
double *const cp; // указатель-константа на
переменную
const double *const cp; // указательконстанта на константу

14. Обращение к указанным переменным и константам

Переменная (константа), адрес которой
хранится в некотором указателе, называется
указанной переменной (константой)
Синтаксис обращения к указанным
переменным и константам:
*<имя указателя>
Здесь символ “*” означает унарную операцию
разадресации, результатом которой является
получение значения из ячейки памяти, адрес
которой хранится в указателе

15. Инициализация указателей на переменные и константы

1.
Присваивание указателю адреса
существующей переменной (константы):
int a; int *p = &a;
2.
Присваивание значения другого
инициализированного указателя:
int *r = p;
3.
Присваивание пустого значения:
int *p = NULL; int *r = 0;
4.
Присваивание адреса памяти в явном виде
int *p = (int*) 28456;

16. Замечания об инициализации

В первом способе инициализации используется
унарная операция получения адреса
Эта операция может применяться только к
поименованным величинам; нельзя получить
адрес выражения или неименованной
константы
Четвертый способ инициализации
используется в системном программировании
для доступа к ячейкам памяти специального
назначения

17. Важность инициализации

При объявлении указателя надо сразу
выполнять его инициализацию
Непреднамеренное использование
неинициализированных указателей – один из
наиболее распространенных источников
ошибок в программах!

18. Динамические переменные

(константы)
создаются в динамической области памяти
(heap – куча)
Время жизни таких переменных – от момента
создания до завершения программы или до
явного освобождения памяти
Доступ к динамическим переменным и
константам осуществляется с помощью
указателей

19. Создание динамических переменных

происходит в момент выделения им места в
памяти
Для выполнения этой операции можно
используют унарную операцию new
Синтаксис операции:
new <тип> [(<инициализирующее выражение>)]
Например:
int* m = new int;
float* x = new float(56);

20. Удаление динамических переменных

Для удаления динамических переменных и
констант с освобождением памяти используют
унарную операцию delete:
delete <имя указателя>
Память, отведенная под динамические
объекты, автоматически освобождается, когда
указатели на них выходят из области своего
действия

21. Сборка мусора

Вместо использования операций delete можно
просто присваивать переменной-указателю
значение NULL
В этом случае в оперативной памяти остается
неиспользуемая динамических переменная
В состав операционной системы входит
подсистема garbage collector («сборщик
мусора»), назначением которой является
автоматическое удаление из динамической
памяти неиспользуемых переменных

22. Пример программы

Программа «Объявление указателей»
Листинг программы

23. Указатели void

Синтаксис объявления
void *<имя указателя>
Применяется в тех случаях, когда конкретный
тип объекта, адрес которого требуется
хранить, не определен

24. Указатели void

Указателю на void можно присвоить значение
указателя любого типа, но перед выполнением
каких-либо действий с областью памяти, на
которую он ссылается, требуется произвести
явное преобразование к нужному типу
Например:
float a = 7; void *r = &a;
cout << “*r = “ << *(float*)r << endl;

25. Операции с указателями

Кроме четырех рассмотренных выше унарных
операций (*, &, new и delete) для
указателей определены четыре бинарных
арифметических операции:
• инкремент,
• декремент,
• сложение с константой,
• вычитание
Арифметические операции изменяют значения
указателей

26. Операции с указателями

Операция инкремента (декремента)
увеличивает (уменьшает) значение указателя,
связанного с некоторым типом, на величину,
равную размеру данных этого типа
Операции сложения (вычитания) с константой
увеличивают (уменьшают) значение указателя
на величину, равную произведению константы
на размер данных типа, связанного с
указателем

27. Операции с указателями

Разность двух указателей одного типа равна
разности их значений, деленной на размер
данных связанного с ними типа
Суммирование двух указателей не допускается
Например для указателей p и q:
int *p = new int, *q = new int;
разность p – q будет иметь значение в 4 раза
меньшее разности их значений
Листинг программы

28. Указатели и массивы

В языке C++ указатели играют очень важную роль,
обеспечивая ряд особенностей в работе с массивами и строками,
которые отсутствуют в алголоподобных языках типа Pascal

29. Указатели и массивы

В языках C и C++ существует тесная связь
между массивами и указателями – имя массива
фактически является указателем-константой,
инициализированным адресом начального
элемента массива
Поэтому возможна следующая инициализация
указателя:
float a[10]; float* p = a;
без выполнения операция получения адреса,
примененной к имени массива (&a)

30. Указатели и массивы

Для обращения к элементам массива можно
использовать операции адресной арифметики
Например, присваивание
float x = *(a + i);
эквивалентно
float x = a[i];
Пример использования имени массива как
указателя
Выполнение программы

31. Динамические массивы

Использование указателей позволяет
создавать массивы, размер которых
определяется уже в процессе выполнения
программы
Такие массивы принято называть
динамическими
Однако следует иметь в виду, что будучи
однажды заданным размер динамического
массива уже не может быть изменен

32. Создание динамического массива

Для создания динамического массива
необходимо объявить указатель, который
будет играть роль имени массива:
<тип элементов> *<имя массива>
Затем делается запрос на выделение памяти
для размещения массива
<имя массива> = new <тип элементов>
“[“<выражение целого типа>”]”
Значение выражения, помещенного в
квадратные скобки, и будет размером
динамического массива

33. Освобождение памяти

Динамический массив не инициализируется и
его элементы не обнуляются
Например:
cin >> n;
double *a = new double [n];
Освобождение памяти, выделенной под
динамический массив осуществляется
операцией
delete [ ] <имя массива>
Пример работы с динамическим массивом
Листинг программы

34. Двумерные массивы

с фиксированными на
этапе компиляции размерами объявляются
следующим образом:
<тип элементов> <имя массива>
“[“<размер1>”]” “[“<размер2>”]”
[=“{“<список констант>”}”],
где <размер1> и <размер2> – константные
выражения

35. Пример определения двумерного массива

Например:
const int n = 2;
int a [n] [2 * n] = {{1, 3, 5, 7}, {2, 4,
6, 8}};
Здесь описан прямоугольный массив из двух
строк и четырех столбцов
Разбиение списка констант в инициализаторе
на подсписки можно было не производить:
int a [n] [2 * n] = {1, 3, 5, 7, 2, 4, 6,
8};

36. Двумерные массивы

В двумерном массиве a[i] является
указателем-константой на начало i–й строки,
т.е. содержит адрес элемента a[i] [0], поэтому
*(a[i] + j) эквивалентно a[i] [j]
Следовательно, двумерный массив фактически
является одномерным массивом указателей на
одномерные массивы
Этот принцип построения распространяется на
массивы любой размерности

37. Двумерный массив

int a [5] [4]
a
a [0]
a [0] [0]
a [0] [1]
a [0] [2]
a [0] [3]
a [1]
a [1] [0]
a [1] [1]
a [1] [2]
a [1] [3]
a [2]
a [2] [0]
a [2] [1]
a [2] [2]
a [2] [3]
a [3]
a [3] [0]
a [3] [1]
a [3] [2]
a [3] [3]
a 4]
a [4] [0]
a [4] [1]
a [4] [2]
a [4] [3]

38. Динамические двумерные массивы

Для создания динамического двумерного
массива следует объявить указатель на массив
указателей:
<тип элементов*> *<имя массива>
Далее следует запросить выделение памяти под
этот массив:
<имя массива> = new <тип элементов*>
“[“<выражение целого типа>”]”

39. Динамические двумерные массивы

Далее следует инициализировать каждый из
элементов массива указателей:
<имя массива> “[“<индексное
выражение>”]”= new <тип элементов>“[“<
выражение целого типа>”]”

40. Зубчатые массивы

Возможность задавать длину для каждой
строки двумерного массива позволяет
формировать массивы произвольной формы,
отличной от прямоугольной
Такие массивы называются зубчатыми (jagged
arrays)
Пример определения зубчатого массива
Листинг программы
Удаление многомерных динамических массивов
также производится операцией delete [ ]

41. Конец лекции

42. Структура физической памяти

Логическому делению оперативной памяти на
статическую, автоматическую и динамическую
соответствует деление физической памяти на
несколько участков, называемых сегментами
Сегментная структура физической памяти
обеспечивает, кроме того, раздельное хранение
программ и данных

43. Сегменты оперативной памяти

44. Сегменты и виды памяти

Коды функций размещаются в сегменте команд
CS
Статические переменные размещаются в
сегменте данных DS
Автоматические переменные размещаются в
сегменте стека SS
Динамические переменные размещаются в
дополнительном сегменте данных ES

45. Виды указателей

Указатели могут использоваться для доступа
как к статическим (поименованным), так и к
динамическим (непоименованным) объектам
Обращение к самим указателям
осуществляется по имени, также как к другим
статическим переменным
В языке C++ различают три вида указателей:
• указатели на переменные,
• указатели на функции,
• void-указатели

46. Указатели и строки

Пример работы со строками через указатели
Листинг программы
English     Русский Rules